diff options
Diffstat (limited to 'sound/soc/codecs')
384 files changed, 19311 insertions, 6564 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index c6043fa58c74..fc65283031cd 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1345,7 +1345,6 @@ static const struct snd_soc_component_driver soc_component_dev_pm860x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pm860x_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 326f2d611ad4..7022e6286e6c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -41,6 +41,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ADS117X imply SND_SOC_AK4104 imply SND_SOC_AK4118 + imply SND_SOC_AK4375 imply SND_SOC_AK4458 imply SND_SOC_AK4535 imply SND_SOC_AK4554 @@ -52,6 +53,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AK5558 imply SND_SOC_ALC5623 imply SND_SOC_ALC5632 + imply SND_SOC_AW8738 imply SND_SOC_BT_SCO imply SND_SOC_BD28623 imply SND_SOC_CQ0093VC @@ -63,6 +65,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L36 imply SND_SOC_CS35L41_SPI imply SND_SOC_CS35L41_I2C + imply SND_SOC_CS35L45_I2C + imply SND_SOC_CS35L45_SPI imply SND_SOC_CS42L42 imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 @@ -94,6 +98,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_DA9055 imply SND_SOC_DMIC imply SND_SOC_ES8316 + imply SND_SOC_ES8326 imply SND_SOC_ES8328_SPI imply SND_SOC_ES8328_I2C imply SND_SOC_ES7134 @@ -125,6 +130,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_MAX98373_I2C imply SND_SOC_MAX98373_SDW imply SND_SOC_MAX98390 + imply SND_SOC_MAX98396 imply SND_SOC_MAX9850 imply SND_SOC_MAX9860 imply SND_SOC_MAX9759 @@ -166,6 +172,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1011 imply SND_SOC_RT1015 imply SND_SOC_RT1015P + imply SND_SOC_RT1016 imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 @@ -199,6 +206,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SPDIF + imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 imply SND_SOC_SSM2518 imply SND_SOC_SSM2602_SPI @@ -213,6 +221,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS2562 imply SND_SOC_TAS2764 imply SND_SOC_TAS2770 + imply SND_SOC_TAS2780 imply SND_SOC_TAS5086 imply SND_SOC_TAS571X imply SND_SOC_TAS5720 @@ -220,6 +229,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TDA7419 imply SND_SOC_TFA9879 imply SND_SOC_TFA989X + imply SND_SOC_TLV320ADC3XXX imply SND_SOC_TLV320ADCX140 imply SND_SOC_TLV320AIC23_I2C imply SND_SOC_TLV320AIC23_SPI @@ -241,8 +251,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X - imply SND_SOC_WCD937X - imply SND_SOC_WCD938X + imply SND_SOC_WCD938X_SDW + imply SND_SOC_LPASS_MACRO_COMMON imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO imply SND_SOC_WL1273 @@ -262,7 +272,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WM8711 imply SND_SOC_WM8727 imply SND_SOC_WM8728 - imply SND_SOC_WM8731 + imply SND_SOC_WM8731_I2C + imply SND_SOC_WM8731_SPI imply SND_SOC_WM8737 imply SND_SOC_WM8741 imply SND_SOC_WM8750 @@ -300,6 +311,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WM9712 imply SND_SOC_WM9713 imply SND_SOC_WSA881X + imply SND_SOC_WSA883X imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which @@ -343,11 +355,15 @@ config SND_SOC_WM_ADSP default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM2200=y + default y if SND_SOC_CS35L41_SPI=y + default y if SND_SOC_CS35L41_I2C=y default m if SND_SOC_MADERA=m default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM2200=m + default m if SND_SOC_CS35L41_SPI=m + default m if SND_SOC_CS35L41_I2C=m config SND_SOC_AB8500_CODEC tristate @@ -519,6 +535,16 @@ config SND_SOC_AK4118 depends on I2C select REGMAP_I2C +config SND_SOC_AK4375 + tristate "AKM AK4375 CODEC" + depends on I2C + select REGMAP_I2C + help + Enable support for the Asahi-Kasei AK4375 codec. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-ak4375. + config SND_SOC_AK4458 tristate "AKM AK4458 CODEC" depends on I2C @@ -563,6 +589,15 @@ config SND_SOC_ALC5632 tristate depends on I2C +config SND_SOC_AW8738 + tristate "Awinic AW8738 Audio Amplifier" + select GPIOLIB + help + Enable support for the Awinic AW8738 audio amplifier (or similar). + The driver supports simple audio amplifiers similar to + SND_SOC_SIMPLE_AMPLIFIER, but additionally allows setting the + operation mode using the Awinic-specific one-wire pulse control. + config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help @@ -575,7 +610,7 @@ config SND_SOC_BT_SCO config SND_SOC_CPCAP tristate "Motorola CPCAP codec" - depends on MFD_CPCAP + depends on MFD_CPCAP || COMPILE_TEST config SND_SOC_CQ0093VC tristate @@ -609,19 +644,63 @@ config SND_SOC_CS35L36 tristate "Cirrus Logic CS35L36 CODEC" depends on I2C +config SND_SOC_CS35L41_LIB + tristate + +config SND_SOC_CS35L41 + tristate + config SND_SOC_CS35L41_SPI tristate "Cirrus Logic CS35L41 CODEC (SPI)" depends on SPI_MASTER + select SND_SOC_CS35L41_LIB + select SND_SOC_CS35L41 select REGMAP_SPI config SND_SOC_CS35L41_I2C tristate "Cirrus Logic CS35L41 CODEC (I2C)" depends on I2C + select SND_SOC_CS35L41_LIB + select SND_SOC_CS35L41 + select REGMAP_I2C + +config SND_SOC_CS35L45_TABLES + tristate + +config SND_SOC_CS35L45 + tristate + +config SND_SOC_CS35L45_SPI + tristate "Cirrus Logic CS35L45 CODEC (SPI)" + depends on SPI_MASTER + select REGMAP + select REGMAP_SPI + select SND_SOC_CS35L45_TABLES + select SND_SOC_CS35L45 + help + Enable support for Cirrus Logic CS35L45 smart speaker amplifier + with SPI control. + +config SND_SOC_CS35L45_I2C + tristate "Cirrus Logic CS35L45 CODEC (I2C)" + depends on I2C + select REGMAP select REGMAP_I2C + select SND_SOC_CS35L45_TABLES + select SND_SOC_CS35L45 + help + Enable support for Cirrus Logic CS35L45 smart speaker amplifier + with I2C control. + +config SND_SOC_CS42L42_CORE + tristate config SND_SOC_CS42L42 - tristate "Cirrus Logic CS42L42 CODEC" + tristate "Cirrus Logic CS42L42 CODEC (I2C)" depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS42L42_CORE config SND_SOC_CS42L51 tristate @@ -643,6 +722,13 @@ config SND_SOC_CS42L73 tristate "Cirrus Logic CS42L73 CODEC" depends on I2C +config SND_SOC_CS42L83 + tristate "Cirrus Logic CS42L83 CODEC" + depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS42L42_CORE + config SND_SOC_CS4234 tristate "Cirrus Logic CS4234 CODEC" depends on I2C @@ -708,6 +794,7 @@ config SND_SOC_CS4349 config SND_SOC_CS47L15 tristate + depends on MFD_CS47L15 config SND_SOC_CS47L24 tristate @@ -715,15 +802,19 @@ config SND_SOC_CS47L24 config SND_SOC_CS47L35 tristate + depends on MFD_CS47L35 config SND_SOC_CS47L85 tristate + depends on MFD_CS47L85 config SND_SOC_CS47L90 tristate + depends on MFD_CS47L90 config SND_SOC_CS47L92 tristate + depends on MFD_CS47L92 # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 @@ -817,7 +908,6 @@ config SND_SOC_DA9055 config SND_SOC_DMIC tristate "Generic Digital Microphone CODEC" - depends on GPIOLIB help Enable support for the Generic Digital Microphone CODEC. Select this if your sound card has DMICs. @@ -838,6 +928,10 @@ config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C +config SND_SOC_ES8326 + tristate "Everest Semi ES8326 CODEC" + depends on I2C + config SND_SOC_ES8328 tristate @@ -864,6 +958,16 @@ config SND_SOC_HDAC_HDA tristate select SND_HDA +config SND_SOC_HDA + tristate "HD-Audio codec driver" + select SND_HDA_EXT_CORE + select SND_HDA + help + This enables HD-Audio codec support in ASoC subsystem. Compared + to SND_SOC_HDAC_HDA, driver's behavior is identical to HD-Audio + legacy solution - including the dynamic resource allocation + based on actual codec capabilities. + config SND_SOC_ICS43432 tristate "ICS43423 and compatible i2s microphones" @@ -881,7 +985,7 @@ config SND_SOC_LM49453 config SND_SOC_LOCHNAGAR_SC tristate "Lochnagar Sound Card" - depends on MFD_LOCHNAGAR + depends on MFD_LOCHNAGAR || COMPILE_TEST help This driver support the sound card functionality of the Cirrus Logic Lochnagar audio development board. @@ -913,7 +1017,6 @@ config SND_SOC_MAX98095 config SND_SOC_MAX98357A tristate "Maxim MAX98357A CODEC" - depends on GPIOLIB config SND_SOC_MAX98371 tristate @@ -975,6 +1078,15 @@ config SND_SOC_MAX98390 tristate "Maxim Integrated MAX98390 Speaker Amplifier" depends on I2C +config SND_SOC_MAX98396 + tristate "Analog Devices MAX98396 Speaker Amplifier" + depends on I2C + help + Enable support for Analog Devices MAX98396 audio + amplifier. The device provides a PCM interface for + audio data and a standard I2C interface for control + data communication. + config SND_SOC_MAX9850 tristate depends on I2C @@ -1098,8 +1210,7 @@ config SND_SOC_RK3328 config SND_SOC_RK817 tristate "Rockchip RK817 audio CODEC" - depends on MFD_RK808 - select REGMAP_I2C + depends on MFD_RK808 || COMPILE_TEST config SND_SOC_RL6231 tristate @@ -1173,7 +1284,10 @@ config SND_SOC_RT1015 config SND_SOC_RT1015P tristate - depends on GPIOLIB + +config SND_SOC_RT1016 + tristate + depends on I2C config SND_SOC_RT1019 tristate @@ -1324,7 +1438,6 @@ config SND_SOC_RT9120 tristate "Richtek RT9120 Stereo Class-D Amplifier" depends on I2C select REGMAP_I2C - select GPIOLIB help Enable support for Richtek RT9120 20W, stereo, inductor-less, high-efficiency Class-D audio amplifier. @@ -1368,15 +1481,26 @@ config SND_SOC_SIGMADSP_REGMAP config SND_SOC_SIMPLE_AMPLIFIER tristate "Simple Audio Amplifier" - select GPIOLIB config SND_SOC_SIMPLE_MUX tristate "Simple Audio Mux" - select GPIOLIB + depends on GPIOLIB config SND_SOC_SPDIF tristate "S/PDIF CODEC" +config SND_SOC_SRC4XXX_I2C + tristate "Texas Instruments SRC4XXX DIR/DIT and SRC codecs" + depends on I2C + select SND_SOC_SRC4XXX + help + Enable support for the TI SRC4XXX family of codecs. These include the + scr4392 which has digital receivers, transmitters, and + a sample rate converter, including numerous ports. + +config SND_SOC_SRC4XXX + tristate + config SND_SOC_SSM2305 tristate "Analog Devices SSM2305 Class-D Amplifier" help @@ -1442,6 +1566,13 @@ config SND_SOC_TAS2770 tristate "Texas Instruments TAS2770 speaker amplifier" depends on I2C +config SND_SOC_TAS2780 + tristate "Texas Instruments TAS2780 Mono Audio amplifier" + depends on I2C + help + Enable support for Texas Instruments TAS2780 high-efficiency + digital input mono Class-D audio power amplifiers. + config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C @@ -1460,6 +1591,15 @@ config SND_SOC_TAS5720 Enable support for Texas Instruments TAS5720L/M high-efficiency mono Class-D audio power amplifiers. +config SND_SOC_TAS5805M + tristate "Texas Instruments TAS5805M speaker amplifier" + depends on I2C + help + Enable support for Texas Instruments TAS5805M Class-D + amplifiers. This is a speaker amplifier with an integrated + DSP. DSP configuration for each instance needs to be supplied + via a device-tree attribute. + config SND_SOC_TAS6424 tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier" depends on I2C @@ -1486,6 +1626,14 @@ config SND_SOC_TFA989X Note that the driver currently bypasses the built-in "CoolFlux DSP" and does not support (hardware) volume control. +config SND_SOC_TLV320ADC3XXX + tristate "Texas Instruments TLV320ADC3001/3101 audio ADC" + depends on I2C + depends on GPIOLIB + help + Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 + ADCs. + config SND_SOC_TLV320AIC23 tristate @@ -1609,8 +1757,10 @@ config SND_SOC_WCD_MBHC config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK + depends on SLIMBUS + select REGMAP_SLIMBUS select SND_SOC_WCD_MBHC - depends on MFD_WCD934X + depends on MFD_WCD934X || COMPILE_TEST help The WCD9340/9341 is a audio codec IC Integrated in Qualcomm SoCs like SDM845. @@ -1699,8 +1849,19 @@ config SND_SOC_WM8728 depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8731 - tristate "Wolfson Microelectronics WM8731 CODEC" - depends on SND_SOC_I2C_AND_SPI + tristate + +config SND_SOC_WM8731_I2C + tristate "Wolfson Microelectronics WM8731 CODEC with I2C" + depends on I2C + select REGMAP + select SND_SOC_WM8731 + +config SND_SOC_WM8731_SPI + tristate "Wolfson Microelectronics WM8731 CODEC with SPI" + depends on SPI + select REGMAP + select SND_SOC_WM8731 config SND_SOC_WM8737 tristate "Wolfson Microelectronics WM8737 ADC" @@ -1757,7 +1918,7 @@ config SND_SOC_WM8904 depends on I2C config SND_SOC_WM8940 - tristate + tristate "Wolfson Microelectronics WM8940 codec" depends on I2C config SND_SOC_WM8955 @@ -1866,10 +2027,18 @@ config SND_SOC_WSA881X This enables support for Qualcomm WSA8810/WSA8815 Class-D Smart Speaker Amplifier. +config SND_SOC_WSA883X + tristate "WSA883X Codec" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + tristate + help + This enables support for Qualcomm WSA8830/WSA8835 Class-D + Smart Speaker Amplifier. + config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" depends on SPI_MASTER - select GPIOLIB select REGMAP help Support for ZL38060 Connected Home Audio Processor from Microsemi, @@ -1883,7 +2052,7 @@ config SND_SOC_LM4857 config SND_SOC_MAX9759 tristate "Maxim MAX9759 speaker Amplifier" - select GPIOLIB + depends on GPIOLIB config SND_SOC_MAX9768 tristate @@ -1966,6 +2135,9 @@ config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C +config SND_SOC_LPASS_MACRO_COMMON + tristate + config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK select REGMAP_MMIO @@ -1974,16 +2146,19 @@ config SND_SOC_LPASS_WSA_MACRO config SND_SOC_LPASS_VA_MACRO depends on COMMON_CLK select REGMAP_MMIO + select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_RX_MACRO depends on COMMON_CLK select REGMAP_MMIO + select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_TX_MACRO depends on COMMON_CLK select REGMAP_MMIO + select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9acfbcbfc46d..9170ee1447dd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -34,6 +34,7 @@ snd-soc-adav803-objs := adav803.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4118-objs := ak4118.o +snd-soc-ak4375-objs := ak4375.o snd-soc-ak4458-objs := ak4458.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak4554-objs := ak4554.o @@ -44,6 +45,7 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-ak5558-objs := ak5558.o snd-soc-arizona-objs := arizona.o arizona-jack.o +snd-soc-aw8738-objs := aw8738.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-cpcap-objs := cpcap.o @@ -54,14 +56,22 @@ snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs35l36-objs := cs35l36.o -snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41.o cs35l41-tables.o -snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-lib-objs := cs35l41-lib.o +snd-soc-cs35l41-objs := cs35l41.o +snd-soc-cs35l41-spi-objs := cs35l41-spi.o +snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o +snd-soc-cs35l45-tables-objs := cs35l45-tables.o +snd-soc-cs35l45-objs := cs35l45.o +snd-soc-cs35l45-spi-objs := cs35l45-spi.o +snd-soc-cs35l45-i2c-objs := cs35l45-i2c.o snd-soc-cs42l42-objs := cs42l42.o +snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o snd-soc-cs42l56-objs := cs42l56.o snd-soc-cs42l73-objs := cs42l73.o +snd-soc-cs42l83-i2c-objs := cs42l83-i2c.o snd-soc-cs4234-objs := cs4234.o snd-soc-cs4265-objs := cs4265.o snd-soc-cs4270-objs := cs4270.o @@ -92,12 +102,14 @@ snd-soc-dmic-objs := dmic.o snd-soc-es7134-objs := es7134.o snd-soc-es7241-objs := es7241.o snd-soc-es8316-objs := es8316.o +snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-hdac-hda-objs := hdac_hda.o +snd-soc-hda-codec-objs := hda.o hda-dai.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -109,6 +121,7 @@ snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-lochnagar-sc-objs := lochnagar-sc.o +snd-soc-lpass-macro-common-objs := lpass-macro-common.o snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o @@ -130,6 +143,7 @@ snd-soc-max98373-objs := max98373.o snd-soc-max98373-i2c-objs := max98373-i2c.o snd-soc-max98373-sdw-objs := max98373-sdw.o snd-soc-max98390-objs := max98390.o +snd-soc-max98396-objs := max98396.o snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o @@ -176,6 +190,7 @@ snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o +snd-soc-rt1016-objs := rt1016.o snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o @@ -219,6 +234,8 @@ snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-rx-objs := spdif_receiver.o +snd-soc-src4xxx-objs := src4xxx.o +snd-soc-src4xxx-i2c-objs := src4xxx-i2c.o snd-soc-ssm2305-objs := ssm2305.o snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2602-objs := ssm2602.o @@ -233,11 +250,13 @@ snd-soc-sti-sas-objs := sti-sas.o snd-soc-tas5086-objs := tas5086.o snd-soc-tas571x-objs := tas571x.o snd-soc-tas5720-objs := tas5720.o +snd-soc-tas5805m-objs := tas5805m.o snd-soc-tas6424-objs := tas6424.o snd-soc-tda7419-objs := tda7419.o snd-soc-tas2770-objs := tas2770.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tfa989x-objs := tfa989x.o +snd-soc-tlv320adc3xxx-objs := tlv320adc3xxx.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o @@ -283,6 +302,8 @@ snd-soc-wm8711-objs := wm8711.o snd-soc-wm8727-objs := wm8727.o snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o +snd-soc-wm8731-i2c-objs := wm8731-i2c.o +snd-soc-wm8731-spi-objs := wm8731-spi.o snd-soc-wm8737-objs := wm8737.o snd-soc-wm8741-objs := wm8741.o snd-soc-wm8750-objs := wm8750.o @@ -322,6 +343,7 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-wsa881x-objs := wsa881x.o +snd-soc-wsa883x-objs := wsa883x.o snd-soc-zl38060-objs := zl38060.o # Amp snd-soc-max9877-objs := max9877.o @@ -331,6 +353,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o snd-soc-tas2562-objs := tas2562.o snd-soc-tas2764-objs := tas2764.o +snd-soc-tas2780-objs := tas2780.o # Mux snd-soc-simple-mux-objs := simple-mux.o @@ -369,6 +392,7 @@ obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o +obj-$(CONFIG_SND_SOC_AK4375) += snd-soc-ak4375.o obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o @@ -381,6 +405,7 @@ obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o +obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o @@ -391,14 +416,22 @@ obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o +obj-$(CONFIG_SND_SOC_CS35L41) += snd-soc-cs35l41.o +obj-$(CONFIG_SND_SOC_CS35L41_LIB) += snd-soc-cs35l41-lib.o obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o -obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o +obj-$(CONFIG_SND_SOC_CS35L45_TABLES) += snd-soc-cs35l45-tables.o +obj-$(CONFIG_SND_SOC_CS35L45) += snd-soc-cs35l45.o +obj-$(CONFIG_SND_SOC_CS35L45_SPI) += snd-soc-cs35l45-spi.o +obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o +obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o +obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o +obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o @@ -429,12 +462,14 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o +obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o +obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o @@ -463,6 +498,7 @@ obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o obj-$(CONFIG_SND_SOC_MAX98373_I2C) += snd-soc-max98373-i2c.o obj-$(CONFIG_SND_SOC_MAX98373_SDW) += snd-soc-max98373-sdw.o obj-$(CONFIG_SND_SOC_MAX98390) += snd-soc-max98390.o +obj-$(CONFIG_SND_SOC_MAX98396) += snd-soc-max98396.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o @@ -509,6 +545,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o +obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o @@ -550,6 +587,8 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o +obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o +obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o @@ -564,14 +603,17 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o +obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o +obj-$(CONFIG_SND_SOC_TAS5805M) += snd-soc-tas5805m.o obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TFA989X) += snd-soc-tfa989x.o +obj-$(CONFIG_SND_SOC_TLV320ADC3XXX) += snd-soc-tlv320adc3xxx.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o @@ -619,6 +661,8 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o +obj-$(CONFIG_SND_SOC_WM8731_I2C) += snd-soc-wm8731-i2c.o +obj-$(CONFIG_SND_SOC_WM8731_SPI) += snd-soc-wm8731-spi.o obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o @@ -659,6 +703,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o +obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp @@ -666,6 +711,7 @@ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-$(CONFIG_SND_SOC_LPASS_MACRO_COMMON) += snd-soc-lpass-macro-common.o obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO) += snd-soc-lpass-va-macro.o obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO) += snd-soc-lpass-rx-macro.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index aefafb0b7b97..68342917419e 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -12,8 +12,6 @@ * Mikko Sarmanne <mikko.sarmanne@symbio.com>, * Jarmo K. Kuronen <jarmo.kuronen@symbio.com>, * for ST-Ericsson. - * - * License terms: */ #include <linux/kernel.h> @@ -2525,7 +2523,6 @@ static const struct snd_soc_component_driver ab8500_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ab8500_codec_driver_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h index 0ac87d0446c2..2a6f6409f1f8 100644 --- a/sound/soc/codecs/ab8500-codec.h +++ b/sound/soc/codecs/ab8500-codec.h @@ -11,8 +11,6 @@ * Mikko J. Lehto <mikko.lehto@symbio.com>, * Mikko Sarmanne <mikko.sarmanne@symbio.com>, * for ST-Ericsson. - * - * License terms: */ #ifndef AB8500_CODEC_REGISTERS_H diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 6ad9c9443b5d..cc12052e1920 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -119,7 +119,6 @@ static const struct snd_soc_component_driver soc_component_dev_ac97 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ac97_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 29e1689da67f..2c64df96b5ce 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -332,7 +332,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1836 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct reg_default ad1836_reg_defaults[] = { diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c index 3d509a65e4ca..4cb8d87f9011 100644 --- a/sound/soc/codecs/ad193x-i2c.c +++ b/sound/soc/codecs/ad193x-i2c.c @@ -20,10 +20,10 @@ static const struct i2c_device_id ad193x_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad193x_id); -static int ad193x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ad193x_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(ad193x_id, client); config = ad193x_regmap_config; config.val_bits = 8; @@ -38,7 +38,7 @@ static struct i2c_driver ad193x_i2c_driver = { .driver = { .name = "ad193x", }, - .probe = ad193x_i2c_probe, + .probe_new = ad193x_i2c_probe, .id_table = ad193x_id, }; module_i2c_driver(ad193x_i2c_driver); diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 30b98b4267e1..1d3c4d94b4ae 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -523,7 +523,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad193x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct regmap_config ad193x_regmap_config = { diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 9fd2023da218..5e777d7fd5d9 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -302,7 +302,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1980 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ad1980_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index b98bf19f594e..f6090ac57e93 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -58,7 +58,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad73311 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ad73311_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index fc87a76ff1ee..8ed0ffdedbc9 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -14,7 +14,7 @@ #include "adau1372.h" -static int adau1372_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int adau1372_i2c_probe(struct i2c_client *client) { return adau1372_probe(&client->dev, devm_regmap_init_i2c(client, &adau1372_regmap_config), NULL); @@ -30,7 +30,7 @@ static struct i2c_driver adau1372_i2c_driver = { .driver = { .name = "adau1372", }, - .probe = adau1372_i2c_probe, + .probe_new = adau1372_i2c_probe, .id_table = adau1372_i2c_ids, }; module_i2c_driver(adau1372_i2c_driver); diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 1faa4c426365..a9f89e8565ec 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -859,6 +859,7 @@ static const struct snd_soc_component_driver adau1372_driver = { .num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets), .dapm_routes = adau1372_dapm_routes, .num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops adau1372_dai_ops = { diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 46128aaceae9..7f832d00ab17 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1470,11 +1470,9 @@ static const struct snd_soc_component_driver adau1373_component_driver = { .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int adau1373_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1373_i2c_probe(struct i2c_client *client) { struct adau1373 *adau1373; int ret; @@ -1508,7 +1506,7 @@ static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", }, - .probe = adau1373_i2c_probe, + .probe_new = adau1373_i2c_probe, .id_table = adau1373_i2c_id, }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index c5bf461c0b7e..135a7db7fcf9 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -13,8 +13,8 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/of_device.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <sound/core.h> @@ -106,8 +106,8 @@ static const char * const supply_names[] = { }; struct adau1701 { - int gpio_nreset; - int gpio_pll_mode[2]; + struct gpio_desc *gpio_nreset; + struct gpio_descs *gpio_pll_mode; unsigned int dai_fmt; unsigned int pll_clkdiv; unsigned int sysclk; @@ -303,39 +303,41 @@ static int adau1701_reset(struct snd_soc_component *component, unsigned int clkd struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component); int ret; + DECLARE_BITMAP(values, 2); sigmadsp_reset(adau1701->sigmadsp); - if (clkdiv != ADAU1707_CLKDIV_UNSET && - gpio_is_valid(adau1701->gpio_pll_mode[0]) && - gpio_is_valid(adau1701->gpio_pll_mode[1])) { + if (clkdiv != ADAU1707_CLKDIV_UNSET && adau1701->gpio_pll_mode) { switch (clkdiv) { case 64: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); + __assign_bit(0, values, 0); + __assign_bit(1, values, 0); break; case 256: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); + __assign_bit(0, values, 0); + __assign_bit(1, values, 1); break; case 384: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); + __assign_bit(0, values, 1); + __assign_bit(1, values, 0); break; - case 0: /* fallback */ + case 0: /* fallback */ case 512: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); + __assign_bit(0, values, 1); + __assign_bit(1, values, 1); break; } + gpiod_set_array_value_cansleep(adau1701->gpio_pll_mode->ndescs, + adau1701->gpio_pll_mode->desc, adau1701->gpio_pll_mode->info, + values); } adau1701->pll_clkdiv = clkdiv; - if (gpio_is_valid(adau1701->gpio_nreset)) { - gpio_set_value_cansleep(adau1701->gpio_nreset, 0); + if (adau1701->gpio_nreset) { + gpiod_set_value_cansleep(adau1701->gpio_nreset, 0); /* minimum reset time is 20ns */ udelay(1); - gpio_set_value_cansleep(adau1701->gpio_nreset, 1); + gpiod_set_value_cansleep(adau1701->gpio_nreset, 1); /* power-up time may be as long as 85ms */ mdelay(85); } @@ -719,8 +721,8 @@ static void adau1701_remove(struct snd_soc_component *component) { struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(adau1701->gpio_nreset)) - gpio_set_value_cansleep(adau1701->gpio_nreset, 0); + if (adau1701->gpio_nreset) + gpiod_set_value_cansleep(adau1701->gpio_nreset, 0); regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); } @@ -770,7 +772,6 @@ static const struct snd_soc_component_driver adau1701_component_drv = { .set_sysclk = adau1701_set_sysclk, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config adau1701_regmap = { @@ -783,13 +784,10 @@ static const struct regmap_config adau1701_regmap = { .reg_read = adau1701_reg_read, }; -static int adau1701_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adau1701_i2c_probe(struct i2c_client *client) { struct adau1701 *adau1701; struct device *dev = &client->dev; - int gpio_nreset = -EINVAL; - int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; int ret, i; adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); @@ -823,26 +821,6 @@ static int adau1701_i2c_probe(struct i2c_client *client, if (dev->of_node) { - gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); - if (gpio_nreset < 0 && gpio_nreset != -ENOENT) { - ret = gpio_nreset; - goto exit_regulators_disable; - } - - gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, - "adi,pll-mode-gpios", 0); - if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) { - ret = gpio_pll_mode[0]; - goto exit_regulators_disable; - } - - gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, - "adi,pll-mode-gpios", 1); - if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) { - ret = gpio_pll_mode[1]; - goto exit_regulators_disable; - } - of_property_read_u32(dev->of_node, "adi,pll-clkdiv", &adau1701->pll_clkdiv); @@ -851,32 +829,20 @@ static int adau1701_i2c_probe(struct i2c_client *client, ARRAY_SIZE(adau1701->pin_config)); } - if (gpio_is_valid(gpio_nreset)) { - ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, - "ADAU1701 Reset"); - if (ret < 0) - goto exit_regulators_disable; + adau1701->gpio_nreset = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + + if (IS_ERR(adau1701->gpio_nreset)) { + ret = PTR_ERR(adau1701->gpio_nreset); + goto exit_regulators_disable; } - if (gpio_is_valid(gpio_pll_mode[0]) && - gpio_is_valid(gpio_pll_mode[1])) { - ret = devm_gpio_request_one(dev, gpio_pll_mode[0], - GPIOF_OUT_INIT_LOW, - "ADAU1701 PLL mode 0"); - if (ret < 0) - goto exit_regulators_disable; + adau1701->gpio_pll_mode = devm_gpiod_get_array_optional(dev, "adi,pll-mode", GPIOD_OUT_LOW); - ret = devm_gpio_request_one(dev, gpio_pll_mode[1], - GPIOF_OUT_INIT_LOW, - "ADAU1701 PLL mode 1"); - if (ret < 0) - goto exit_regulators_disable; + if (IS_ERR(adau1701->gpio_pll_mode)) { + ret = PTR_ERR(adau1701->gpio_pll_mode); + goto exit_regulators_disable; } - adau1701->gpio_nreset = gpio_nreset; - adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; - adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; - i2c_set_clientdata(client, adau1701); adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, @@ -910,7 +876,7 @@ static struct i2c_driver adau1701_i2c_driver = { .name = "adau1701", .of_match_table = of_match_ptr(adau1701_dt_ids), }, - .probe = adau1701_i2c_probe, + .probe_new = adau1701_i2c_probe, .id_table = adau1701_i2c_id, }; diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index c8fce37e5cfa..0cefff49569c 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -14,10 +14,12 @@ #include "adau1761.h" -static int adau1761_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1761_i2c_ids[]; + +static int adau1761_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1761_i2c_ids, client); config = adau1761_regmap_config; config.val_bits = 8; @@ -28,10 +30,9 @@ static int adau1761_i2c_probe(struct i2c_client *client, id->driver_data, NULL); } -static int adau1761_i2c_remove(struct i2c_client *client) +static void adau1761_i2c_remove(struct i2c_client *client) { adau17x1_remove(&client->dev); - return 0; } static const struct i2c_device_id adau1761_i2c_ids[] = { @@ -59,7 +60,7 @@ static struct i2c_driver adau1761_i2c_driver = { .name = "adau1761", .of_match_table = of_match_ptr(adau1761_i2c_dt_ids), }, - .probe = adau1761_i2c_probe, + .probe_new = adau1761_i2c_probe, .remove = adau1761_i2c_remove, .id_table = adau1761_i2c_ids, }; diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index 655689c9778a..7c9242c2ff94 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c @@ -45,10 +45,9 @@ static int adau1761_spi_probe(struct spi_device *spi) id->driver_data, adau1761_spi_switch_mode); } -static int adau1761_spi_remove(struct spi_device *spi) +static void adau1761_spi_remove(struct spi_device *spi) { adau17x1_remove(&spi->dev); - return 0; } static const struct spi_device_id adau1761_spi_id[] = { diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index fb006fc81653..3ccc7acac205 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -556,8 +556,6 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { { "Left DAC", NULL, "Interpolator Resync Clock" }, { "Right DAC", NULL, "Interpolator Resync Clock" }, - { "DSP", NULL, "Digital Clock 0" }, - { "Slew Clock", NULL, "Digital Clock 0" }, { "Right Playback Mixer", NULL, "Slew Clock" }, { "Left Playback Mixer", NULL, "Slew Clock" }, @@ -569,6 +567,56 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { { "Digital Clock 1", NULL, "SYSCLK" }, }; +static const struct snd_soc_dapm_route adau1761_dapm_dsp_routes[] = { + { "DSP", NULL, "Digital Clock 0" }, +}; + +static int adau1761_compatibility_probe(struct device *dev) +{ + struct adau *adau = dev_get_drvdata(dev); + struct regmap *regmap = adau->regmap; + int val, ret = 0; + + /* Only consider compatibility mode when ADAU1361 was specified. */ + if (adau->type != ADAU1361) + return 0; + + regcache_cache_bypass(regmap, true); + + /* + * This will enable the core clock and bypass the PLL, + * so that we can access the registers for probing purposes + * (without having to set up the PLL). + */ + regmap_write(regmap, ADAU17X1_CLOCK_CONTROL, + ADAU17X1_CLOCK_CONTROL_SYSCLK_EN); + + /* + * ADAU17X1_SERIAL_SAMPLING_RATE doesn't exist in non-DSP chips; + * reading it results in zero at all times, and write is a no-op. + * Use this register to probe for ADAU1761. + */ + regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 1); + ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val); + if (ret) + goto exit; + if (val != 1) + goto exit; + regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 0); + ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val); + if (ret) + goto exit; + if (val != 0) + goto exit; + + adau->type = ADAU1761_AS_1361; +exit: + /* Disable core clock after probing. */ + regmap_write(regmap, ADAU17X1_CLOCK_CONTROL, 0); + regcache_cache_bypass(regmap, false); + return ret; +} + static int adau1761_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -823,7 +871,11 @@ static int adau1761_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (adau->type == ADAU1761) { + /* + * If we've got an ADAU1761, or an ADAU1761 operating as an + * ADAU1361, we need these non-DSP related DAPM widgets and routes. + */ + if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361) { ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets, ARRAY_SIZE(adau1761_dapm_widgets)); if (ret) @@ -834,7 +886,29 @@ static int adau1761_component_probe(struct snd_soc_component *component) if (ret) return ret; } - + /* + * These routes are DSP related and only used when we have a + * bona fide ADAU1761. + */ + if (adau->type == ADAU1761) { + ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_dsp_routes, + ARRAY_SIZE(adau1761_dapm_dsp_routes)); + if (ret) + return ret; + } + /* + * In the ADAU1761, by default, the AIF is routed to the DSP, whereas + * for the ADAU1361, the AIF is permanently routed to the ADC and DAC. + * Thus, if we have an ADAU1761 masquerading as an ADAU1361, + * we need to explicitly route the AIF to the ADC and DAC. + * For the ADAU1761, this is normally done by set_tdm_slot, but this + * function is not necessarily called during stream setup, so set up + * the compatible AIF routings here from the start. + */ + if (adau->type == ADAU1761_AS_1361) { + regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE, 0x01); + regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x01); + } ret = adau17x1_add_routes(component); if (ret < 0) return ret; @@ -856,7 +930,6 @@ static const struct snd_soc_component_driver adau1761_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ @@ -919,6 +992,10 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; + ret = adau1761_compatibility_probe(dev); + if (ret) + return ret; + /* Enable cache only mode as we could miss writes before bias level * reaches standby and the core clock is enabled */ regcache_cache_only(regmap, true); diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 1c476429ad99..39021b8cfb62 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -14,10 +14,12 @@ #include "adau1781.h" -static int adau1781_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1781_i2c_ids[]; + +static int adau1781_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1781_i2c_ids, client); config = adau1781_regmap_config; config.val_bits = 8; @@ -28,10 +30,9 @@ static int adau1781_i2c_probe(struct i2c_client *client, id->driver_data, NULL); } -static int adau1781_i2c_remove(struct i2c_client *client) +static void adau1781_i2c_remove(struct i2c_client *client) { adau17x1_remove(&client->dev); - return 0; } static const struct i2c_device_id adau1781_i2c_ids[] = { @@ -55,7 +56,7 @@ static struct i2c_driver adau1781_i2c_driver = { .name = "adau1781", .of_match_table = of_match_ptr(adau1781_i2c_dt_ids), }, - .probe = adau1781_i2c_probe, + .probe_new = adau1781_i2c_probe, .remove = adau1781_i2c_remove, .id_table = adau1781_i2c_ids, }; diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index bb5613574786..1a09633d5a88 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c @@ -45,10 +45,9 @@ static int adau1781_spi_probe(struct spi_device *spi) id->driver_data, adau1781_spi_switch_mode); } -static int adau1781_spi_remove(struct spi_device *spi) +static void adau1781_spi_remove(struct spi_device *spi) { adau17x1_remove(&spi->dev); - return 0; } static const struct spi_device_id adau1781_spi_id[] = { diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 74dc3344b259..ff6be24863bf 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -439,7 +439,6 @@ static const struct snd_soc_component_driver adau1781_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index af05463af4ac..c0f44ecef606 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -334,6 +334,17 @@ static bool adau17x1_has_dsp(struct adau *adau) } } +/* Chip has a DSP but we're pretending it doesn't. */ +static bool adau17x1_has_disused_dsp(struct adau *adau) +{ + switch (adau->type) { + case ADAU1761_AS_1361: + return true; + default: + return false; + } +} + static bool adau17x1_has_safeload(struct adau *adau) { switch (adau->type) { @@ -516,10 +527,11 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, ADAU17X1_CONVERTER0_CONVSR_MASK, div); - if (adau17x1_has_dsp(adau)) { + + if (adau17x1_has_dsp(adau) || adau17x1_has_disused_dsp(adau)) regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div); + if (adau17x1_has_dsp(adau)) regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); - } if (adau->sigmadsp) { ret = adau17x1_setup_firmware(component, params_rate(params)); @@ -663,7 +675,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, switch (slot_width * slots) { case 32: - if (adau->type == ADAU1761) + if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361) return -EINVAL; ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32; @@ -738,7 +750,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1); - if (!adau17x1_has_dsp(adau)) + if (!adau17x1_has_dsp(adau) && !adau17x1_has_disused_dsp(adau)) return 0; if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) { diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 98a3b6f5bc96..5e58abfffc3d 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -10,6 +10,7 @@ enum adau17x1_type { ADAU1361, ADAU1761, + ADAU1761_AS_1361, ADAU1381, ADAU1781, }; diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index 82a49c85d536..9f137a0634d5 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -14,10 +14,12 @@ #include "adau1977.h" -static int adau1977_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adau1977_i2c_ids[]; + +static int adau1977_i2c_probe(struct i2c_client *client) { struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(adau1977_i2c_ids, client); config = adau1977_regmap_config; config.val_bits = 8; @@ -40,7 +42,7 @@ static struct i2c_driver adau1977_i2c_driver = { .driver = { .name = "adau1977", }, - .probe = adau1977_i2c_probe, + .probe_new = adau1977_i2c_probe, .id_table = adau1977_i2c_ids, }; module_i2c_driver(adau1977_i2c_driver); diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 5fcbdf2ec313..7a9672f94fc6 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -876,7 +876,6 @@ static const struct snd_soc_component_driver adau1977_component_driver = { .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int adau1977_setup_micbias(struct adau1977 *adau1977) diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index 0e00de6ce3fb..401bafabc8eb 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -91,7 +91,6 @@ static const struct snd_soc_component_driver adau7002_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int adau7002_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index aa7afb3b826d..afed48401b25 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -48,8 +48,7 @@ static const struct regmap_config adau7118_regmap_config = { .volatile_reg = adau7118_volatile, }; -static int adau7118_probe_i2c(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int adau7118_probe_i2c(struct i2c_client *i2c) { struct regmap *map; @@ -79,7 +78,7 @@ static struct i2c_driver adau7118_driver = { .name = "adau7118", .of_match_table = adau7118_of_match, }, - .probe = adau7118_probe_i2c, + .probe_new = adau7118_probe_i2c, .id_table = adau7118_id, }; module_i2c_driver(adau7118_driver); diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c index 841229dcbca1..bbb097249887 100644 --- a/sound/soc/codecs/adau7118.c +++ b/sound/soc/codecs/adau7118.c @@ -442,7 +442,6 @@ static const struct snd_soc_component_driver adau7118_component_driver = { .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void adau7118_regulator_disable(void *data) diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c index 0f565b851ea5..bf181bbaabed 100644 --- a/sound/soc/codecs/adav803.c +++ b/sound/soc/codecs/adav803.c @@ -19,8 +19,7 @@ static const struct i2c_device_id adav803_id[] = { }; MODULE_DEVICE_TABLE(i2c, adav803_id); -static int adav803_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adav803_probe(struct i2c_client *client) { return adav80x_bus_probe(&client->dev, devm_regmap_init_i2c(client, &adav80x_regmap_config)); @@ -30,7 +29,7 @@ static struct i2c_driver adav803_driver = { .driver = { .name = "adav803", }, - .probe = adav803_probe, + .probe_new = adav803_probe, .id_table = adav803_id, }; module_i2c_driver(adav803_driver); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 90f3a5e9e31f..fcff35f26cec 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -842,7 +842,6 @@ static const struct snd_soc_component_driver adav80x_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int adav80x_bus_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 1d07e2699f04..44aa06e03486 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -62,7 +62,6 @@ static const struct snd_soc_component_driver soc_component_dev_ads117x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ads117x_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index dc4747c77a7a..ce99f30b4613 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -248,7 +248,6 @@ static const struct snd_soc_component_driver soc_component_device_ak4104 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4104_regmap = { diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index e0a6451851e8..b6d9a10bdccd 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -342,7 +342,6 @@ static const struct snd_soc_component_driver soc_component_drv_ak4118 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4118_regmap = { @@ -356,8 +355,7 @@ static const struct regmap_config ak4118_regmap = { .max_register = AK4118_REG_MAX - 1, }; -static int ak4118_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4118_i2c_probe(struct i2c_client *i2c) { struct ak4118_priv *ak4118; int ret; @@ -374,20 +372,14 @@ static int ak4118_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, ak4118); ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ak4118->reset)) { - ret = PTR_ERR(ak4118->reset); - if (ret != -EPROBE_DEFER) - dev_err(&i2c->dev, "Failed to get reset: %d\n", ret); - return ret; - } + if (IS_ERR(ak4118->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->reset), + "Failed to get reset\n"); ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN); - if (IS_ERR(ak4118->irq)) { - ret = PTR_ERR(ak4118->irq); - if (ret != -EPROBE_DEFER) - dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret); - return ret; - } + if (IS_ERR(ak4118->irq)) + return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->irq), + "Failed to get IRQ\n"); ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq), NULL, ak4118_irq_handler, @@ -422,7 +414,7 @@ static struct i2c_driver ak4118_i2c_driver = { .of_match_table = of_match_ptr(ak4118_of_match), }, .id_table = ak4118_id_table, - .probe = ak4118_i2c_probe, + .probe_new = ak4118_i2c_probe, }; module_i2c_driver(ak4118_i2c_driver); diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c new file mode 100644 index 000000000000..573389e402f8 --- /dev/null +++ b/sound/soc/codecs/ak4375.c @@ -0,0 +1,607 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Based on code by Hu Jin + * Copyright (C) 2014 Asahi Kasei Microdevices Corporation + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +/* Registers and fields */ +#define AK4375_00_POWER_MANAGEMENT1 0x00 +#define PMPLL BIT(0) /* 0: PLL off, 1: PLL on */ +#define AK4375_01_POWER_MANAGEMENT2 0x01 +#define PMCP1 BIT(0) /* Charge Pump 1: LDO1 and DAC */ +#define PMCP2 BIT(1) /* Charge Pump 2: Class-G HP Amp */ +#define PMLDO1P BIT(4) +#define PMLDO1N BIT(5) +#define PMLDO (PMLDO1P | PMLDO1N) +#define AK4375_02_POWER_MANAGEMENT3 0x02 +#define AK4375_03_POWER_MANAGEMENT4 0x03 +#define AK4375_04_OUTPUT_MODE_SETTING 0x04 +#define AK4375_05_CLOCK_MODE_SELECT 0x05 +#define FS_MASK GENMASK(4, 0) +#define FS_8KHZ 0x00 +#define FS_11_025KHZ 0x01 +#define FS_16KHZ 0x04 +#define FS_22_05KHZ 0x05 +#define FS_32KHZ 0x08 +#define FS_44_1KHZ 0x09 +#define FS_48KHZ 0x0a +#define FS_88_2KHZ 0x0d +#define FS_96KHZ 0x0e +#define FS_176_4KHZ 0x11 +#define FS_192KHZ 0x12 +#define CM_MASK GENMASK(6, 5) /* For SRC Bypass mode */ +#define CM_0 (0x0 << 5) +#define CM_1 (0x1 << 5) +#define CM_2 (0x2 << 5) +#define CM_3 (0x3 << 5) +#define AK4375_06_DIGITAL_FILTER_SELECT 0x06 +#define DADFSEL BIT(5) /* 0: in SRC Bypass mode, 1: in SRC mode */ +#define DASL BIT(6) +#define DASD BIT(7) +#define AK4375_07_DAC_MONO_MIXING 0x07 +#define DACMUTE_MASK (GENMASK(5, 4) | GENMASK(1, 0)) /* Clear to mute */ +#define AK4375_08_JITTER_CLEANER_SETTING1 0x08 +#define AK4375_09_JITTER_CLEANER_SETTING2 0x09 +#define AK4375_0A_JITTER_CLEANER_SETTING3 0x0a +#define SELDAIN BIT(1) /* 0: SRC Bypass mode, 1: SRC mode */ +#define XCKSEL BIT(6) /* 0: PLL0, 1: MCKI */ +#define XCKCPSEL BIT(7) /* Should be equal to SELDAIN and XCKSEL */ +#define AK4375_0B_LCH_OUTPUT_VOLUME 0x0b +#define AK4375_0C_RCH_OUTPUT_VOLUME 0x0c +#define AK4375_0D_HP_VOLUME_CONTROL 0x0d +#define AK4375_0E_PLL_CLK_SOURCE_SELECT 0x0e +#define PLS BIT(0) /* 0: MCKI, 1: BCLK */ +#define AK4375_0F_PLL_REF_CLK_DIVIDER1 0x0f /* Reference clock divider [15:8] bits */ +#define AK4375_10_PLL_REF_CLK_DIVIDER2 0x10 /* Reference clock divider [7:0] bis */ +#define AK4375_11_PLL_FB_CLK_DIVIDER1 0x11 /* Feedback clock divider [15:8] bits */ +#define AK4375_12_PLL_FB_CLK_DIVIDER2 0x12 /* Feedback clock divider [7:0] bits */ +#define AK4375_13_SRC_CLK_SOURCE 0x13 /* SRC Bypass: SRCCKS=XCKSEL=SELDAIN=0 */ +#define SRCCKS BIT(0) /* SRC Clock source 0: MCKI, 1: PLL0 */ +#define DIV BIT(4) +#define AK4375_14_DAC_CLK_DIVIDER 0x14 +#define AK4375_15_AUDIO_IF_FORMAT 0x15 +#define DEVICEID_MASK GENMASK(7, 5) +#define AK4375_24_MODE_CONTROL 0x24 + +#define AK4375_PLL_FREQ_OUT_112896000 112896000 /* 44.1 kHz base rate */ +#define AK4375_PLL_FREQ_OUT_122880000 122880000 /* 32 and 48 kHz base rates */ + +#define DEVICEID_AK4375 0x00 +#define DEVICEID_AK4375A 0x01 +#define DEVICEID_AK4376A 0x02 +#define DEVICEID_AK4377 0x03 +#define DEVICEID_AK4331 0x07 + +static const char * const supply_names[] = { + "avdd", "tvdd" +}; + +struct ak4375_drvdata { + struct snd_soc_dai_driver *dai_drv; + const struct snd_soc_component_driver *comp_drv; +}; + +struct ak4375_priv { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *pdn_gpiod; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + unsigned int rate; + unsigned int pld; + u8 mute_save; +}; + +static const struct reg_default ak4375_reg_defaults[] = { + { 0x00, 0x00 }, { 0x01, 0x00 }, { 0x02, 0x00 }, + { 0x03, 0x00 }, { 0x04, 0x00 }, { 0x05, 0x00 }, + { 0x06, 0x00 }, { 0x07, 0x00 }, { 0x08, 0x00 }, + { 0x09, 0x00 }, { 0x0a, 0x00 }, { 0x0b, 0x19 }, + { 0x0c, 0x19 }, { 0x0d, 0x75 }, { 0x0e, 0x01 }, + { 0x0f, 0x00 }, { 0x10, 0x00 }, { 0x11, 0x00 }, + { 0x12, 0x00 }, { 0x13, 0x00 }, { 0x14, 0x00 }, + { 0x15, 0x00 }, { 0x24, 0x00 }, +}; + +/* + * Output Digital volume control: + * from -12.5 to 3 dB in 0.5 dB steps (mute instead of -12.5 dB) + */ +static DECLARE_TLV_DB_SCALE(dac_tlv, -1250, 50, 0); + +/* + * HP-Amp Analog volume control: + * from -4.2 to 6 dB in 2 dB steps (mute instead of -4.2 dB) + */ +static DECLARE_TLV_DB_SCALE(hpg_tlv, -4200, 20, 0); + +static const char * const ak4375_ovolcn_select_texts[] = { "Dependent", "Independent" }; +static const char * const ak4375_mdac_select_texts[] = { "x1", "x1/2" }; +static const char * const ak4375_cpmode_select_texts[] = { + "Automatic Switching", + "+-VDD Operation", + "+-1/2VDD Operation" +}; + +/* + * DASD, DASL bits Digital Filter Setting + * 0, 0 : Sharp Roll-Off Filter + * 0, 1 : Slow Roll-Off Filter + * 1, 0 : Short delay Sharp Roll-Off Filter + * 1, 1 : Short delay Slow Roll-Off Filter + */ +static const char * const ak4375_digfil_select_texts[] = { + "Sharp Roll-Off Filter", + "Slow Roll-Off Filter", + "Short delay Sharp Roll-Off Filter", + "Short delay Slow Roll-Off Filter", +}; + +static const struct soc_enum ak4375_ovolcn_enum = + SOC_ENUM_SINGLE(AK4375_0B_LCH_OUTPUT_VOLUME, 7, + ARRAY_SIZE(ak4375_ovolcn_select_texts), ak4375_ovolcn_select_texts); +static const struct soc_enum ak4375_mdacl_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 2, + ARRAY_SIZE(ak4375_mdac_select_texts), ak4375_mdac_select_texts); +static const struct soc_enum ak4375_mdacr_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 6, + ARRAY_SIZE(ak4375_mdac_select_texts), ak4375_mdac_select_texts); +static const struct soc_enum ak4375_cpmode_enum = + SOC_ENUM_SINGLE(AK4375_03_POWER_MANAGEMENT4, 2, + ARRAY_SIZE(ak4375_cpmode_select_texts), ak4375_cpmode_select_texts); +static const struct soc_enum ak4375_digfil_enum = + SOC_ENUM_SINGLE(AK4375_06_DIGITAL_FILTER_SELECT, 6, + ARRAY_SIZE(ak4375_digfil_select_texts), ak4375_digfil_select_texts); + +static const struct snd_kcontrol_new ak4375_snd_controls[] = { + SOC_DOUBLE_R_TLV("Digital Output Volume", AK4375_0B_LCH_OUTPUT_VOLUME, + AK4375_0C_RCH_OUTPUT_VOLUME, 0, 0x1f, 0, dac_tlv), + SOC_SINGLE_TLV("HP-Amp Analog Volume", + AK4375_0D_HP_VOLUME_CONTROL, 0, 0x1f, 0, hpg_tlv), + + SOC_DOUBLE("DAC Signal Invert Switch", AK4375_07_DAC_MONO_MIXING, 3, 7, 1, 0), + + SOC_ENUM("Digital Volume Control", ak4375_ovolcn_enum), + SOC_ENUM("DACL Signal Level", ak4375_mdacl_enum), + SOC_ENUM("DACR Signal Level", ak4375_mdacr_enum), + SOC_ENUM("Charge Pump Mode", ak4375_cpmode_enum), + SOC_ENUM("DAC Digital Filter Mode", ak4375_digfil_enum), +}; + +static const struct snd_kcontrol_new ak4375_hpl_mixer_controls[] = { + SOC_DAPM_SINGLE("LDACL Switch", AK4375_07_DAC_MONO_MIXING, 0, 1, 0), + SOC_DAPM_SINGLE("RDACL Switch", AK4375_07_DAC_MONO_MIXING, 1, 1, 0), +}; + +static const struct snd_kcontrol_new ak4375_hpr_mixer_controls[] = { + SOC_DAPM_SINGLE("LDACR Switch", AK4375_07_DAC_MONO_MIXING, 4, 1, 0), + SOC_DAPM_SINGLE("RDACR Switch", AK4375_07_DAC_MONO_MIXING, 5, 1, 0), +}; + +static int ak4375_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, AK4375_00_POWER_MANAGEMENT1, PMPLL, PMPLL); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP1, PMCP1); + usleep_range(6500, 7000); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMLDO, PMLDO); + usleep_range(1000, 2000); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP2, PMCP2); + usleep_range(4500, 5000); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP2, 0x0); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMLDO, 0x0); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP1, 0x0); + snd_soc_component_update_bits(component, AK4375_00_POWER_MANAGEMENT1, PMPLL, 0x0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget ak4375_dapm_widgets[] = { + SND_SOC_DAPM_DAC_E("DAC", NULL, AK4375_02_POWER_MANAGEMENT3, 0, 0, ak4375_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_IN("SDTI", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + + SND_SOC_DAPM_MIXER("HPR Mixer", AK4375_03_POWER_MANAGEMENT4, 1, 0, + &ak4375_hpr_mixer_controls[0], ARRAY_SIZE(ak4375_hpr_mixer_controls)), + SND_SOC_DAPM_MIXER("HPL Mixer", AK4375_03_POWER_MANAGEMENT4, 0, 0, + &ak4375_hpl_mixer_controls[0], ARRAY_SIZE(ak4375_hpl_mixer_controls)), +}; + +static const struct snd_soc_dapm_route ak4375_intercon[] = { + { "DAC", NULL, "SDTI" }, + + { "HPL Mixer", "LDACL Switch", "DAC" }, + { "HPL Mixer", "RDACL Switch", "DAC" }, + { "HPR Mixer", "LDACR Switch", "DAC" }, + { "HPR Mixer", "RDACR Switch", "DAC" }, + + { "HPL", NULL, "HPL Mixer" }, + { "HPR", NULL, "HPR Mixer" }, +}; + +static int ak4375_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + unsigned int freq_in, freq_out; + + ak4375->rate = params_rate(params); + + if (ak4375->rate <= 96000) + ak4375->pld = 0; + else + ak4375->pld = 1; + + freq_in = 32 * ak4375->rate / (ak4375->pld + 1); + + if ((ak4375->rate % 8000) == 0) + freq_out = AK4375_PLL_FREQ_OUT_122880000; + else + freq_out = AK4375_PLL_FREQ_OUT_112896000; + + return snd_soc_dai_set_pll(dai, 0, 0, freq_in, freq_out); +} + +static int ak4375_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + unsigned int mclk, plm, mdiv, div; + u8 cms, fs, cm; + + cms = snd_soc_component_read(component, AK4375_05_CLOCK_MODE_SELECT); + fs = cms & ~FS_MASK; + cm = cms & ~CM_MASK; + + switch (ak4375->rate) { + case 8000: + fs |= FS_8KHZ; + break; + case 11025: + fs |= FS_11_025KHZ; + break; + case 16000: + fs |= FS_16KHZ; + break; + case 22050: + fs |= FS_22_05KHZ; + break; + case 32000: + fs |= FS_32KHZ; + break; + case 44100: + fs |= FS_44_1KHZ; + break; + case 48000: + fs |= FS_48KHZ; + break; + case 88200: + fs |= FS_88_2KHZ; + break; + case 96000: + fs |= FS_96KHZ; + break; + case 176400: + fs |= FS_176_4KHZ; + break; + case 192000: + fs |= FS_192KHZ; + break; + default: + return -EINVAL; + } + + if (ak4375->rate <= 24000) { + cm |= CM_1; + mclk = 512 * ak4375->rate; + mdiv = freq_out / mclk - 1; + div = 0; + } else if (ak4375->rate <= 96000) { + cm |= CM_0; + mclk = 256 * ak4375->rate; + mdiv = freq_out / mclk - 1; + div = 0; + } else { + cm |= CM_3; + mclk = 128 * ak4375->rate; + mdiv = 4; + div = 1; + } + + /* Writing both fields in one go seems to make playback choppy on start */ + snd_soc_component_update_bits(component, AK4375_05_CLOCK_MODE_SELECT, FS_MASK, fs); + snd_soc_component_update_bits(component, AK4375_05_CLOCK_MODE_SELECT, CM_MASK, cm); + + snd_soc_component_write(component, AK4375_0F_PLL_REF_CLK_DIVIDER1, + (ak4375->pld & 0xff00) >> 8); + snd_soc_component_write(component, AK4375_10_PLL_REF_CLK_DIVIDER2, + ak4375->pld & 0x00ff); + + plm = freq_out / freq_in - 1; + snd_soc_component_write(component, AK4375_11_PLL_FB_CLK_DIVIDER1, (plm & 0xff00) >> 8); + snd_soc_component_write(component, AK4375_12_PLL_FB_CLK_DIVIDER2, plm & 0x00ff); + + snd_soc_component_update_bits(component, AK4375_13_SRC_CLK_SOURCE, DIV, div); + + /* SRCCKS bit: force to 1 for SRC PLL source clock */ + snd_soc_component_update_bits(component, AK4375_13_SRC_CLK_SOURCE, SRCCKS, SRCCKS); + + snd_soc_component_write(component, AK4375_14_DAC_CLK_DIVIDER, mdiv); + + dev_dbg(ak4375->dev, "rate=%d mclk=%d f_in=%d f_out=%d PLD=%d PLM=%d MDIV=%d DIV=%d\n", + ak4375->rate, mclk, freq_in, freq_out, ak4375->pld, plm, mdiv, div); + + return 0; +} + +static int ak4375_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + u8 val = snd_soc_component_read(component, AK4375_07_DAC_MONO_MIXING); + + dev_dbg(ak4375->dev, "mute=%d val=%d\n", mute, val); + + if (mute) { + ak4375->mute_save = val & DACMUTE_MASK; + val &= ~DACMUTE_MASK; + } else { + val |= ak4375->mute_save; + } + + snd_soc_component_write(component, AK4375_07_DAC_MONO_MIXING, val); + + return 0; +} + +#define AK4375_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define AK4375_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops ak4375_dai_ops = { + .hw_params = ak4375_hw_params, + .mute_stream = ak4375_mute, + .set_pll = ak4375_dai_set_pll, +}; + +static struct snd_soc_dai_driver ak4375_dai = { + .name = "ak4375-hifi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4375_RATES, + .rate_min = 8000, + .rate_max = 192000, + .formats = AK4375_FORMATS, + }, + .ops = &ak4375_dai_ops, +}; + +static void ak4375_power_off(struct ak4375_priv *ak4375) +{ + gpiod_set_value_cansleep(ak4375->pdn_gpiod, 0); + usleep_range(1000, 2000); + + regulator_bulk_disable(ARRAY_SIZE(ak4375->supplies), ak4375->supplies); +} + +static int ak4375_power_on(struct ak4375_priv *ak4375) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ak4375->supplies), ak4375->supplies); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + usleep_range(3000, 4000); + + gpiod_set_value_cansleep(ak4375->pdn_gpiod, 1); + usleep_range(1000, 2000); + + return 0; +} + +static int __maybe_unused ak4375_runtime_suspend(struct device *dev) +{ + struct ak4375_priv *ak4375 = dev_get_drvdata(dev); + + regcache_cache_only(ak4375->regmap, true); + ak4375_power_off(ak4375); + + return 0; +} + +static int __maybe_unused ak4375_runtime_resume(struct device *dev) +{ + struct ak4375_priv *ak4375 = dev_get_drvdata(dev); + int ret; + + ret = ak4375_power_on(ak4375); + if (ret < 0) + return ret; + + regcache_cache_only(ak4375->regmap, false); + regcache_mark_dirty(ak4375->regmap); + + return regcache_sync(ak4375->regmap); +} + +static const struct snd_soc_component_driver soc_codec_dev_ak4375 = { + .controls = ak4375_snd_controls, + .num_controls = ARRAY_SIZE(ak4375_snd_controls), + .dapm_widgets = ak4375_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4375_dapm_widgets), + .dapm_routes = ak4375_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4375_intercon), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config ak4375_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AK4375_24_MODE_CONTROL, + .reg_defaults = ak4375_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4375_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static const struct ak4375_drvdata ak4375_drvdata = { + .dai_drv = &ak4375_dai, + .comp_drv = &soc_codec_dev_ak4375, +}; + +static const struct dev_pm_ops ak4375_pm = { + SET_RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static int ak4375_i2c_probe(struct i2c_client *i2c) +{ + struct ak4375_priv *ak4375; + const struct ak4375_drvdata *drvdata; + unsigned int deviceid; + int ret, i; + + ak4375 = devm_kzalloc(&i2c->dev, sizeof(*ak4375), GFP_KERNEL); + if (!ak4375) + return -ENOMEM; + + ak4375->regmap = devm_regmap_init_i2c(i2c, &ak4375_regmap); + if (IS_ERR(ak4375->regmap)) + return PTR_ERR(ak4375->regmap); + + i2c_set_clientdata(i2c, ak4375); + ak4375->dev = &i2c->dev; + + drvdata = of_device_get_match_data(&i2c->dev); + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + ak4375->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(ak4375->dev, ARRAY_SIZE(ak4375->supplies), ak4375->supplies); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to get regulators: %d\n", ret); + return ret; + } + + ak4375->pdn_gpiod = devm_gpiod_get_optional(ak4375->dev, "pdn", GPIOD_OUT_LOW); + if (IS_ERR(ak4375->pdn_gpiod)) + return dev_err_probe(ak4375->dev, PTR_ERR(ak4375->pdn_gpiod), + "failed to get pdn\n"); + + ret = ak4375_power_on(ak4375); + if (ret < 0) + return ret; + + /* Don't read deviceid from cache */ + regcache_cache_bypass(ak4375->regmap, true); + + ret = regmap_read(ak4375->regmap, AK4375_15_AUDIO_IF_FORMAT, &deviceid); + if (ret < 0) { + dev_err(ak4375->dev, "unable to read DEVICEID!\n"); + return ret; + } + + regcache_cache_bypass(ak4375->regmap, false); + + deviceid = (deviceid & DEVICEID_MASK) >> 5; + + switch (deviceid) { + case DEVICEID_AK4331: + dev_err(ak4375->dev, "found untested AK4331\n"); + return -EINVAL; + case DEVICEID_AK4375: + dev_dbg(ak4375->dev, "found AK4375\n"); + break; + case DEVICEID_AK4375A: + dev_dbg(ak4375->dev, "found AK4375A\n"); + break; + case DEVICEID_AK4376A: + dev_err(ak4375->dev, "found unsupported AK4376/A!\n"); + return -EINVAL; + case DEVICEID_AK4377: + dev_err(ak4375->dev, "found unsupported AK4377!\n"); + return -EINVAL; + default: + dev_err(ak4375->dev, "unrecognized DEVICEID!\n"); + return -EINVAL; + } + + pm_runtime_set_active(ak4375->dev); + pm_runtime_enable(ak4375->dev); + + ret = devm_snd_soc_register_component(ak4375->dev, drvdata->comp_drv, + drvdata->dai_drv, 1); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to register CODEC: %d\n", ret); + return ret; + } + + return 0; +} + +static void ak4375_i2c_remove(struct i2c_client *i2c) +{ + pm_runtime_disable(&i2c->dev); +} + +static const struct of_device_id ak4375_of_match[] = { + { .compatible = "asahi-kasei,ak4375", .data = &ak4375_drvdata }, + { }, +}; +MODULE_DEVICE_TABLE(of, ak4375_of_match); + +static struct i2c_driver ak4375_i2c_driver = { + .driver = { + .name = "ak4375", + .pm = &ak4375_pm, + .of_match_table = ak4375_of_match, + }, + .probe_new = ak4375_i2c_probe, + .remove = ak4375_i2c_remove, +}; +module_i2c_driver(ak4375_i2c_driver); + +MODULE_AUTHOR("Vincent Knecht <vincent.knecht@mailoo.org>"); +MODULE_DESCRIPTION("ASoC AK4375 DAC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index baa9ff5d0ce5..1db73552c746 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -447,6 +447,13 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, AK4458_0B_CONTROL7, AK4458_DCHAIN_MASK, dchn); + if (ak4458->drvdata->type == AK4497) { + ret = snd_soc_component_update_bits(component, AK4458_09_DSD2, + 0x4, (ak4458->dsd_path << 2)); + if (ret < 0) + return ret; + } + ret = ak4458_rstn_control(component, 0); if (ret) return ret; @@ -629,48 +636,6 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active) } } -static int ak4458_init(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - int ret; - - /* External Mute ON */ - if (ak4458->mute_gpiod) - gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); - - ak4458_reset(ak4458, false); - - ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1, - 0x80, 0x80); /* ACKS bit = 1; 10000000 */ - if (ret < 0) - return ret; - - if (ak4458->drvdata->type == AK4497) { - ret = snd_soc_component_update_bits(component, AK4458_09_DSD2, - 0x4, (ak4458->dsd_path << 2)); - if (ret < 0) - return ret; - } - - return ak4458_rstn_control(component, 1); -} - -static int ak4458_probe(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - - ak4458->fs = 48000; - - return ak4458_init(component); -} - -static void ak4458_remove(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - - ak4458_reset(ak4458, true); -} - #ifdef CONFIG_PM static int __maybe_unused ak4458_runtime_suspend(struct device *dev) { @@ -714,8 +679,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev) #endif /* CONFIG_PM */ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { - .probe = ak4458_probe, - .remove = ak4458_remove, .controls = ak4458_snd_controls, .num_controls = ARRAY_SIZE(ak4458_snd_controls), .dapm_widgets = ak4458_dapm_widgets, @@ -725,12 +688,9 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { - .probe = ak4458_probe, - .remove = ak4458_remove, .controls = ak4497_snd_controls, .num_controls = ARRAY_SIZE(ak4497_snd_controls), .dapm_widgets = ak4497_dapm_widgets, @@ -740,7 +700,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4458_regmap = { @@ -822,15 +781,17 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) pm_runtime_enable(&i2c->dev); regcache_cache_only(ak4458->regmap, true); + ak4458_reset(ak4458, false); return 0; } -static int ak4458_i2c_remove(struct i2c_client *i2c) +static void ak4458_i2c_remove(struct i2c_client *i2c) { - pm_runtime_disable(&i2c->dev); + struct ak4458_priv *ak4458 = i2c_get_clientdata(i2c); - return 0; + ak4458_reset(ak4458, true); + pm_runtime_disable(&i2c->dev); } static const struct of_device_id ak4458_of_match[] = { diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 91e7a57c43da..8c8c93eea704 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -402,11 +402,9 @@ static const struct snd_soc_component_driver soc_component_dev_ak4535 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int ak4535_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4535_i2c_probe(struct i2c_client *i2c) { struct ak4535_priv *ak4535; int ret; @@ -441,7 +439,7 @@ static struct i2c_driver ak4535_i2c_driver = { .driver = { .name = "ak4535", }, - .probe = ak4535_i2c_probe, + .probe_new = ak4535_i2c_probe, .id_table = ak4535_i2c_id, }; diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c index 8e60e2b56ad6..b9607de5a191 100644 --- a/sound/soc/codecs/ak4554.c +++ b/sound/soc/codecs/ak4554.c @@ -67,7 +67,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4554 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ak4554_soc_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 4d2e78101f28..f75c19ef3551 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -10,11 +10,97 @@ // Based on ak4535.c by Richard Purdie // Based on wm8753.c by Liam Girdwood +/* + * +-------+ + * |AK4613 | + * SDTO1 <-| | + * | | + * SDTI1 ->| | + * SDTI2 ->| | + * SDTI3 ->| | + * +-------+ + * + * +---+ + * clk | |___________________________________________... + * + * [TDM512] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4][L5][R5][L6][R6] + * + * [TDM256] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4] + * SDTI2 [L5][R5][L6][R6] + * + * [TDM128] + * SDTO1 [L1][R1][L2][R2] + * SDTI1 [L1][R1][L2][R2] + * SDTI2 [L3][R3][L4][R4] + * SDTI3 [L5][R5][L6][R6] + * + * [STEREO] + * Playback 2ch : SDTI1 + * Capture 2ch : SDTO1 + * + * [TDM512] + * Playback 12ch : SDTI1 + * Capture 4ch : SDTO1 + * + * [TDM256] + * Playback 12ch : SDTI1 + SDTI2 + * Playback 8ch : SDTI1 + * Capture 4ch : SDTO1 + * + * [TDM128] + * Playback 12ch : SDTI1 + SDTI2 + SDTI3 + * Playback 8ch : SDTI1 + SDTI2 + * Playback 4ch : SDTI1 + * Capture 4ch : SDTO1 + * + * + * !!! NOTE !!! + * + * Renesas is the only user of ak4613 on upstream so far, + * but the chip connection is like below. + * Thus, Renesas can't test all connection case. + * Tested TDM is very limited. + * + * +-----+ +-----------+ + * | SoC | | AK4613 | + * | |<-----|SDTO1 IN1|<-- Mic + * | | | IN2| + * | | | | + * | |----->|SDTI1 OUT1|--> Headphone + * +-----+ |SDTI2 OUT2| + * |SDTI3 OUT3| + * | OUT4| + * | OUT5| + * | OUT6| + * +-----------+ + * + * Renesas SoC can handle [2, 6,8] channels. + * Ak4613 can handle [2,4, 8,12] channels. + * + * Because of above HW connection and available channels number, + * Renesas could test are ... + * + * [STEREO] Playback 2ch : SDTI1 + * Capture 2ch : SDTO1 + * [TDM256] Playback 8ch : SDTI1 (*) + * + * (*) it used 8ch data between SoC <-> AK4613 on TDM256 mode, + * but could confirm is only first 2ch because only 1 + * Headphone is connected. + * + * see + * AK4613_ENABLE_TDM_TEST + */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/module.h> #include <linux/regmap.h> #include <sound/soc.h> @@ -78,29 +164,74 @@ /* OCTRL */ #define OCTRL_MASK (0x3F) -struct ak4613_formats { - unsigned int width; - unsigned int fmt; -}; +/* + * configs + * + * 0x000000BA + * + * B : AK4613_CONFIG_SDTI_x + * A : AK4613_CONFIG_MODE_x + */ +#define AK4613_CONFIG_SET(priv, x) priv->configs |= AK4613_CONFIG_##x +#define AK4613_CONFIG_GET(priv, x) (priv->configs & AK4613_CONFIG_##x##_MASK) + +/* + * AK4613_CONFIG_SDTI_x + * + * It indicates how many SDTIx is connected. + */ +#define AK4613_CONFIG_SDTI_MASK (0xF << 4) +#define AK4613_CONFIG_SDTI(x) (((x) & 0xF) << 4) +#define AK4613_CONFIG_SDTI_set(priv, x) AK4613_CONFIG_SET(priv, SDTI(x)) +#define AK4613_CONFIG_SDTI_get(priv) ((AK4613_CONFIG_GET(priv, SDTI) >> 4) & 0xF) + +/* + * AK4613_CONFIG_MODE_x + * + * Same as Ctrl1 :: TDM1/TDM0 + * No shift is requested + * see + * AK4613_CTRL1_TO_MODE() + * Table 11/12/13/14 + */ +#define AK4613_CONFIG_MODE_MASK (0xF) +#define AK4613_CONFIG_MODE_STEREO (0x0) +#define AK4613_CONFIG_MODE_TDM512 (0x1) +#define AK4613_CONFIG_MODE_TDM256 (0x2) +#define AK4613_CONFIG_MODE_TDM128 (0x3) + +/* + * !!!! FIXME !!!! + * + * Because of testable HW limitation, TDM256 8ch TDM was only tested. + * This driver uses AK4613_ENABLE_TDM_TEST instead of new DT property so far. + * Don't hesitate to update driver, you don't need to care compatible + * with Renesas. + * + * #define AK4613_ENABLE_TDM_TEST + */ struct ak4613_interface { - struct ak4613_formats capture; - struct ak4613_formats playback; + unsigned int width; + unsigned int fmt; + u8 dif; }; struct ak4613_priv { struct mutex lock; - const struct ak4613_interface *iface; - struct snd_pcm_hw_constraint_list constraint; + struct snd_pcm_hw_constraint_list constraint_rates; + struct snd_pcm_hw_constraint_list constraint_channels; struct work_struct dummy_write_work; struct snd_soc_component *component; unsigned int rate; unsigned int sysclk; unsigned int fmt; + unsigned int configs; + int cnt; + u8 ctrl1; u8 oc; u8 ic; - int cnt; }; /* @@ -137,14 +268,24 @@ static const struct reg_default ak4613_reg[] = { { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 }, }; -#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3) -#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt } +/* + * CTRL1 register + * see + * Table 11/12/13/14 + */ +#define AUDIO_IFACE(_dif, _width, _fmt) \ + { \ + .dif = _dif, \ + .width = _width, \ + .fmt = SND_SOC_DAIFMT_##_fmt,\ + } static const struct ak4613_interface ak4613_iface[] = { - /* capture */ /* playback */ - /* [0] - [2] are not supported */ - [3] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, LEFT_J) }, - [4] = { AUDIO_IFACE(24, I2S), AUDIO_IFACE(24, I2S) }, + /* It doesn't support asymmetric format */ + + AUDIO_IFACE(0x03, 24, LEFT_J), + AUDIO_IFACE(0x04, 24, I2S), }; +#define AK4613_CTRL1_TO_MODE(priv) ((priv)->ctrl1 >> 6) /* AK4613_CONFIG_MODE_x */ static const struct regmap_config ak4613_regmap_cfg = { .reg_bits = 8, @@ -250,13 +391,14 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, priv->cnt = 0; } if (!priv->cnt) - priv->iface = NULL; + priv->ctrl1 = 0; mutex_unlock(&priv->lock); } static void ak4613_hw_constraints(struct ak4613_priv *priv, - struct snd_pcm_runtime *runtime) + struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; static const unsigned int ak4613_rates[] = { 32000, 44100, @@ -267,10 +409,36 @@ static void ak4613_hw_constraints(struct ak4613_priv *priv, 176400, 192000, }; - struct snd_pcm_hw_constraint_list *constraint = &priv->constraint; +#define AK4613_CHANNEL_2 0 +#define AK4613_CHANNEL_4 1 +#define AK4613_CHANNEL_8 2 +#define AK4613_CHANNEL_12 3 +#define AK4613_CHANNEL_NONE -1 + static const unsigned int ak4613_channels[] = { + [AK4613_CHANNEL_2] = 2, + [AK4613_CHANNEL_4] = 4, + [AK4613_CHANNEL_8] = 8, + [AK4613_CHANNEL_12] = 12, + }; +#define MODE_MAX 4 +#define SDTx_MAX 4 +#define MASK(x) (1 << AK4613_CHANNEL_##x) + static const int mask_list[MODE_MAX][SDTx_MAX] = { + /* SDTO SDTIx1 SDTIx2 SDTIx3 */ + [AK4613_CONFIG_MODE_STEREO] = { MASK(2), MASK(2), MASK(2), MASK(2)}, + [AK4613_CONFIG_MODE_TDM512] = { MASK(4), MASK(12), MASK(12), MASK(12)}, + [AK4613_CONFIG_MODE_TDM256] = { MASK(4), MASK(8), MASK(8)|MASK(12), MASK(8)|MASK(12)}, + [AK4613_CONFIG_MODE_TDM128] = { MASK(4), MASK(4), MASK(4)|MASK(8), MASK(4)|MASK(8)|MASK(12)}, + }; + struct snd_pcm_hw_constraint_list *constraint; + unsigned int mask; + unsigned int mode; unsigned int fs; + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int sdti_num; int i; + constraint = &priv->constraint_rates; constraint->list = ak4613_rates; constraint->mask = 0; constraint->count = 0; @@ -296,6 +464,41 @@ static void ak4613_hw_constraints(struct ak4613_priv *priv, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint); + + + sdti_num = AK4613_CONFIG_SDTI_get(priv); + if (WARN_ON(sdti_num >= SDTx_MAX)) + return; + + if (priv->cnt) { + /* + * If it was already working, + * the constraint is same as working mode. + */ + mode = AK4613_CTRL1_TO_MODE(priv); + mask = 0; /* no default */ + } else { + /* + * It is not yet working, + * the constraint is based on board configs. + * STEREO mask is default + */ + mode = AK4613_CONFIG_GET(priv, MODE); + mask = mask_list[AK4613_CONFIG_MODE_STEREO][is_play * sdti_num]; + } + + if (WARN_ON(mode >= MODE_MAX)) + return; + + /* add each mode mask */ + mask |= mask_list[mode][is_play * sdti_num]; + + constraint = &priv->constraint_channels; + constraint->list = ak4613_channels; + constraint->mask = mask; + constraint->count = sizeof(ak4613_channels); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, constraint); } static int ak4613_dai_startup(struct snd_pcm_substream *substream, @@ -304,9 +507,10 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); + mutex_lock(&priv->lock); + ak4613_hw_constraints(priv, substream); priv->cnt++; - - ak4613_hw_constraints(priv, substream->runtime); + mutex_unlock(&priv->lock); return 0; } @@ -322,13 +526,13 @@ static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai, return 0; } -static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); + unsigned int fmt; - fmt &= SND_SOC_DAIFMT_FORMAT_MASK; - + fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; switch (fmt) { case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_I2S: @@ -338,24 +542,20 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - return 0; -} - -static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface, - int is_play, - unsigned int fmt, unsigned int width) -{ - const struct ak4613_formats *fmts; - - fmts = (is_play) ? &iface->playback : &iface->capture; - - if (fmts->fmt != fmt) - return false; - - if (fmts->width != width) - return false; + fmt = format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + switch (fmt) { + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + /* + * SUPPORTME + * + * "clock provider" is not yet supperted + */ + return -EINVAL; + } - return true; + return 0; } static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, @@ -364,14 +564,12 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - const struct ak4613_interface *iface; struct device *dev = component->dev; unsigned int width = params_width(params); unsigned int fmt = priv->fmt; unsigned int rate; - int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int i, ret; - u8 fmt_ctrl, ctrl2; + u8 ctrl2; rate = params_rate(params); switch (rate) { @@ -397,40 +595,51 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, /* * FIXME * - * It doesn't support TDM at this point + * It doesn't have full TDM suppert yet */ - fmt_ctrl = NO_FMT; ret = -EINVAL; - iface = NULL; mutex_lock(&priv->lock); - if (priv->iface) { - if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) - iface = priv->iface; + if (priv->cnt > 1) { + /* + * If it was already working, use current priv->ctrl1 + */ + ret = 0; } else { + /* + * It is not yet working, + */ + unsigned int channel = params_channels(params); + u8 tdm; + + /* STEREO or TDM */ + if (channel == 2) + tdm = AK4613_CONFIG_MODE_STEREO; + else + tdm = AK4613_CONFIG_GET(priv, MODE); + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { - if (!ak4613_dai_fmt_matching(ak4613_iface + i, - is_play, - fmt, width)) - continue; - iface = ak4613_iface + i; - break; + const struct ak4613_interface *iface = ak4613_iface + i; + + if ((iface->fmt == fmt) && (iface->width == width)) { + /* + * Ctrl1 + * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | + * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| + * < tdm > < iface->dif > + */ + priv->ctrl1 = (tdm << 6) | (iface->dif << 3); + ret = 0; + break; + } } } - - if ((priv->iface == NULL) || - (priv->iface == iface)) { - priv->iface = iface; - ret = 0; - } mutex_unlock(&priv->lock); if (ret < 0) goto hw_params_end; - fmt_ctrl = AUDIO_IFACE_TO_VAL(iface); - - snd_soc_component_update_bits(component, CTRL1, FMT_MASK, fmt_ctrl); + snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); @@ -574,14 +783,14 @@ static struct snd_soc_dai_driver ak4613_dai = { .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 12, .rates = AK4613_PCM_RATE, .formats = AK4613_PCM_FMTBIT, }, .capture = { .stream_name = "Capture", .channels_min = 2, - .channels_max = 2, + .channels_max = 4, .rates = AK4613_PCM_RATE, .formats = AK4613_PCM_FMTBIT, }, @@ -618,7 +827,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4613 = { .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void ak4613_parse_of(struct ak4613_priv *priv, @@ -626,6 +834,7 @@ static void ak4613_parse_of(struct ak4613_priv *priv, { struct device_node *np = dev->of_node; char prop[32]; + int sdti_num; int i; /* Input 1 - 2 */ @@ -641,10 +850,34 @@ static void ak4613_parse_of(struct ak4613_priv *priv, if (!of_get_property(np, prop, NULL)) priv->oc |= 1 << i; } + + /* + * enable TDM256 test + * + * !!! FIXME !!! + * + * It should be configured by DT or other way + * if it was full supported. + * But it is using ifdef style for now for test + * purpose. + */ +#if defined(AK4613_ENABLE_TDM_TEST) + AK4613_CONFIG_SET(priv, MODE_TDM256); +#endif + + /* + * connected STDI + * TDM support is assuming it is probed via Audio-Graph-Card style here. + * Default is SDTIx1 if it was probed via Simple-Audio-Card for now. + */ + sdti_num = of_graph_get_endpoint_count(np); + if ((sdti_num >= SDTx_MAX) || (sdti_num < 1)) + sdti_num = 1; + + AK4613_CONFIG_SDTI_set(priv, sdti_num); } -static int ak4613_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4613_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct device_node *np = dev->of_node; @@ -653,13 +886,11 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, struct ak4613_priv *priv; regmap_cfg = NULL; - if (np) { - const struct of_device_id *of_id; - - of_id = of_match_device(ak4613_of_match, dev); - if (of_id) - regmap_cfg = of_id->data; - } else { + if (np) + regmap_cfg = of_device_get_match_data(dev); + else { + const struct i2c_device_id *id = + i2c_match_id(ak4613_i2c_id, i2c); regmap_cfg = (const struct regmap_config *)id->driver_data; } @@ -672,7 +903,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, ak4613_parse_of(priv, dev); - priv->iface = NULL; + priv->ctrl1 = 0; priv->cnt = 0; priv->sysclk = 0; INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write); @@ -689,18 +920,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, &ak4613_dai, 1); } -static int ak4613_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static struct i2c_driver ak4613_i2c_driver = { .driver = { .name = "ak4613-codec", .of_match_table = ak4613_of_match, }, - .probe = ak4613_i2c_probe, - .remove = ak4613_i2c_remove, + .probe_new = ak4613_i2c_probe, .id_table = ak4613_i2c_id, }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 04aef0e72aa5..0d3ee195b3cc 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -535,7 +535,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4641 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4641_regmap = { @@ -548,8 +547,7 @@ static const struct regmap_config ak4641_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int ak4641_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ak4641_i2c_probe(struct i2c_client *i2c) { struct ak4641_platform_data *pdata = i2c->dev.platform_data; struct ak4641_priv *ak4641; @@ -606,7 +604,7 @@ err_out: return ret; } -static int ak4641_i2c_remove(struct i2c_client *i2c) +static void ak4641_i2c_remove(struct i2c_client *i2c) { struct ak4641_platform_data *pdata = i2c->dev.platform_data; @@ -618,8 +616,6 @@ static int ak4641_i2c_remove(struct i2c_client *i2c) if (gpio_is_valid(pdata->gpio_npdn)) gpio_free(pdata->gpio_npdn); } - - return 0; } static const struct i2c_device_id ak4641_i2c_id[] = { @@ -632,7 +628,7 @@ static struct i2c_driver ak4641_i2c_driver = { .driver = { .name = "ak4641", }, - .probe = ak4641_i2c_probe, + .probe_new = ak4641_i2c_probe, .remove = ak4641_i2c_remove, .id_table = ak4641_i2c_id, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index c284dcc5af76..914d5b1969f8 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -559,7 +559,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4642 = { .num_dapm_routes = ARRAY_SIZE(ak4642_intercon), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4642_regmap = { @@ -630,8 +629,8 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev) #endif static const struct of_device_id ak4642_of_match[]; -static int ak4642_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id ak4642_i2c_id[]; +static int ak4642_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct device_node *np = dev->of_node; @@ -651,6 +650,8 @@ static int ak4642_i2c_probe(struct i2c_client *i2c, if (of_id) drvdata = of_id->data; } else { + const struct i2c_device_id *id = + i2c_match_id(ak4642_i2c_id, i2c); drvdata = (const struct ak4642_drvdata *)id->driver_data; } @@ -697,7 +698,7 @@ static struct i2c_driver ak4642_i2c_driver = { .name = "ak4642-codec", .of_match_table = ak4642_of_match, }, - .probe = ak4642_i2c_probe, + .probe_new = ak4642_i2c_probe, .id_table = ak4642_i2c_id, }; diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index e9d1251c4265..cd76765f8cc0 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -616,7 +616,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4671 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak4671_regmap = { @@ -629,8 +628,7 @@ static const struct regmap_config ak4671_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int ak4671_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ak4671_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -657,7 +655,7 @@ static struct i2c_driver ak4671_i2c_driver = { .driver = { .name = "ak4671-codec", }, - .probe = ak4671_i2c_probe, + .probe_new = ak4671_i2c_probe, .id_table = ak4671_i2c_id, }; diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index c76bfff24602..0c5e00679c7d 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -77,7 +77,6 @@ static const struct snd_soc_component_driver soc_component_ak5386 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index c94cfde3e4a8..60abcffe6a0c 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -393,7 +393,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_codec_dev_ak5552 = { @@ -408,7 +407,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5552 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ak5558_regmap = { @@ -481,11 +479,9 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) return 0; } -static int ak5558_i2c_remove(struct i2c_client *i2c) +static void ak5558_i2c_remove(struct i2c_client *i2c) { pm_runtime_disable(&i2c->dev); - - return 0; } static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = { diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index b10357a6d655..9ef01b1dd294 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -956,7 +956,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5623 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config alc5623_regmap = { @@ -968,14 +967,21 @@ static const struct regmap_config alc5623_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct i2c_device_id alc5623_i2c_table[] = { + {"alc5621", 0x21}, + {"alc5622", 0x22}, + {"alc5623", 0x23}, + {} +}; +MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); + /* * ALC5623 2 wire address is determined by A1 pin * state during powerup. * low = 0x1a * high = 0x1b */ -static int alc5623_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5623_i2c_probe(struct i2c_client *client) { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; @@ -983,6 +989,7 @@ static int alc5623_i2c_probe(struct i2c_client *client, unsigned int vid1, vid2; int ret; u32 val32; + const struct i2c_device_id *id; alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), GFP_KERNEL); @@ -1009,6 +1016,8 @@ static int alc5623_i2c_probe(struct i2c_client *client, } vid2 >>= 8; + id = i2c_match_id(alc5623_i2c_table, client); + if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { dev_err(&client->dev, "unknown or wrong codec\n"); dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n", @@ -1060,14 +1069,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, return ret; } -static const struct i2c_device_id alc5623_i2c_table[] = { - {"alc5621", 0x21}, - {"alc5622", 0x22}, - {"alc5623", 0x23}, - {} -}; -MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); - #ifdef CONFIG_OF static const struct of_device_id alc5623_of_match[] = { { .compatible = "realtek,alc5623", }, @@ -1082,7 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = { .name = "alc562x-codec", .of_match_table = of_match_ptr(alc5623_of_match), }, - .probe = alc5623_i2c_probe, + .probe_new = alc5623_i2c_probe, .id_table = alc5623_i2c_table, }; diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 6d7af3736a91..a770704a4e17 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1078,7 +1078,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5632 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config alc5632_regmap = { @@ -1092,18 +1091,24 @@ static const struct regmap_config alc5632_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct i2c_device_id alc5632_i2c_table[] = { + {"alc5632", 0x5c}, + {} +}; +MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); + /* * alc5632 2 wire address is determined by A1 pin * state during powerup. * low = 0x1a * high = 0x1b */ -static int alc5632_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int alc5632_i2c_probe(struct i2c_client *client) { struct alc5632_priv *alc5632; int ret, ret1, ret2; unsigned int vid1, vid2; + const struct i2c_device_id *id; alc5632 = devm_kzalloc(&client->dev, sizeof(struct alc5632_priv), GFP_KERNEL); @@ -1129,6 +1134,8 @@ static int alc5632_i2c_probe(struct i2c_client *client, vid2 >>= 8; + id = i2c_match_id(alc5632_i2c_table, client); + if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) { dev_err(&client->dev, "Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2); @@ -1161,12 +1168,6 @@ static int alc5632_i2c_probe(struct i2c_client *client, return ret; } -static const struct i2c_device_id alc5632_i2c_table[] = { - {"alc5632", 0x5c}, - {} -}; -MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); - #ifdef CONFIG_OF static const struct of_device_id alc5632_of_match[] = { { .compatible = "realtek,alc5632", }, @@ -1181,7 +1182,7 @@ static struct i2c_driver alc5632_i2c_driver = { .name = "alc5632", .of_match_table = of_match_ptr(alc5632_of_match), }, - .probe = alc5632_i2c_probe, + .probe_new = alc5632_i2c_probe, .id_table = alc5632_i2c_table, }; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e32871b3f68a..7434aeeda292 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1760,8 +1760,8 @@ static bool arizona_aif_cfg_changed(struct snd_soc_component *component, if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK)) return true; - val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE); - if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK)) + val = snd_soc_component_read(component, base + ARIZONA_AIF_RX_BCLK_RATE); + if (lrclk != (val & ARIZONA_AIF1RX_BCPF_MASK)) return true; val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1); diff --git a/sound/soc/codecs/aw8738.c b/sound/soc/codecs/aw8738.c new file mode 100644 index 000000000000..0fe8af160319 --- /dev/null +++ b/sound/soc/codecs/aw8738.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> + +struct aw8738_priv { + struct gpio_desc *gpiod_mode; + unsigned int mode; +}; + +static int aw8738_drv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); + struct aw8738_priv *aw = snd_soc_component_get_drvdata(c); + int i; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + for (i = 0; i < aw->mode; i++) { + gpiod_set_value_cansleep(aw->gpiod_mode, 0); + udelay(2); + gpiod_set_value_cansleep(aw->gpiod_mode, 1); + udelay(2); + } + msleep(40); + break; + case SND_SOC_DAPM_PRE_PMD: + gpiod_set_value_cansleep(aw->gpiod_mode, 0); + usleep_range(1000, 2000); + break; + default: + WARN(1, "Unexpected event"); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_widget aw8738_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, aw8738_drv_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route aw8738_dapm_routes[] = { + { "DRV", NULL, "IN" }, + { "OUT", NULL, "DRV" }, +}; + +static const struct snd_soc_component_driver aw8738_component_driver = { + .dapm_widgets = aw8738_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aw8738_dapm_widgets), + .dapm_routes = aw8738_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aw8738_dapm_routes), +}; + +static int aw8738_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct aw8738_priv *aw; + int ret; + + aw = devm_kzalloc(dev, sizeof(*aw), GFP_KERNEL); + if (!aw) + return -ENOMEM; + platform_set_drvdata(pdev, aw); + + aw->gpiod_mode = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW); + if (IS_ERR(aw->gpiod_mode)) + return dev_err_probe(dev, PTR_ERR(aw->gpiod_mode), + "Failed to get 'mode' gpio"); + + ret = device_property_read_u32(dev, "awinic,mode", &aw->mode); + if (ret) + return -EINVAL; + + return devm_snd_soc_register_component(&pdev->dev, + &aw8738_component_driver, + NULL, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id aw8738_of_match[] = { + { .compatible = "awinic,aw8738" }, + { } +}; +MODULE_DEVICE_TABLE(of, aw8738_of_match); +#endif + +static struct platform_driver aw8738_driver = { + .probe = aw8738_probe, + .driver = { + .name = "aw8738", + .of_match_table = of_match_ptr(aw8738_of_match), + }, +}; +module_platform_driver(aw8738_driver); + +MODULE_DESCRIPTION("Awinic AW8738 Amplifier Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c index a6267cb86d86..82a94211d012 100644 --- a/sound/soc/codecs/bd28623.c +++ b/sound/soc/codecs/bd28623.c @@ -161,7 +161,6 @@ static const struct snd_soc_component_driver soc_codec_bd = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver soc_dai_bd = { diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index 4d286844e3c8..4086b6a53de8 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -13,11 +13,15 @@ static const struct snd_soc_dapm_widget bt_sco_widgets[] = { SND_SOC_DAPM_INPUT("RX"), SND_SOC_DAPM_OUTPUT("TX"), + SND_SOC_DAPM_AIF_IN("BT_SCO_RX", "Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("BT_SCO_TX", "Capture", 0, + SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route bt_sco_routes[] = { - { "Capture", NULL, "RX" }, - { "TX", NULL, "Playback" }, + { "BT_SCO_TX", NULL, "RX" }, + { "TX", NULL, "BT_SCO_RX" }, }; static struct snd_soc_dai_driver bt_sco_dai[] = { @@ -65,7 +69,6 @@ static const struct snd_soc_component_driver soc_component_dev_bt_sco = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int bt_sco_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 598e09024e23..4f9dabd9d78a 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -1660,13 +1660,14 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cpcap_codec_probe(struct platform_device *pdev) { struct device_node *codec_node = of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec"); + if (!codec_node) + return -ENODEV; pdev->dev.of_node = codec_node; diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 0aae5790222a..14403b76c724 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -126,7 +126,6 @@ static const struct snd_soc_component_driver soc_component_dev_cq93vc = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cq93vc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 9b92e1a0d1a3..11e7b3f6d410 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -232,11 +232,11 @@ static int i2s_rx_hw_params(struct snd_pcm_substream *substream, if (params_rate(params) != 48000) return -EINVAL; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_16; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_24; break; default: @@ -387,6 +387,7 @@ static const struct snd_soc_component_driver i2s_rx_component_driver = { .num_dapm_widgets = ARRAY_SIZE(i2s_rx_dapm_widgets), .dapm_routes = i2s_rx_dapm_routes, .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), + .endianness = 1, }; static void *wov_map_shm(struct cros_ec_codec_priv *priv, @@ -994,6 +995,7 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev) dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", priv->ap_shm_phys_addr, priv->ap_shm_len); } + of_node_put(node); } #endif diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 933e3d627e5f..dc7a58d68076 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l32 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Current and threshold powerup sequence Pg37 in datasheet */ @@ -346,8 +345,7 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, return 0; } -static int cs35l32_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l32_i2c_probe(struct i2c_client *i2c_client) { struct cs35l32_private *cs35l32; struct cs35l32_platform_data *pdata = @@ -499,14 +497,12 @@ err_supplies: return ret; } -static int cs35l32_i2c_remove(struct i2c_client *i2c_client) +static void cs35l32_i2c_remove(struct i2c_client *i2c_client) { struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client); /* Hold down reset */ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); - - return 0; } #ifdef CONFIG_PM @@ -576,7 +572,7 @@ static struct i2c_driver cs35l32_i2c_driver = { .of_match_table = cs35l32_of_match, }, .id_table = cs35l32_id, - .probe = cs35l32_i2c_probe, + .probe_new = cs35l32_i2c_probe, .remove = cs35l32_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 2a6f5e46d031..15e79168d256 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -840,7 +840,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l33 = { .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs35l33_regmap = { @@ -1116,8 +1115,7 @@ static int cs35l33_of_get_pdata(struct device *dev, return 0; } -static int cs35l33_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l33_i2c_probe(struct i2c_client *i2c_client) { struct cs35l33_private *cs35l33; struct cs35l33_pdata *pdata = dev_get_platdata(&i2c_client->dev); @@ -1252,7 +1250,7 @@ err_enable: return ret; } -static int cs35l33_i2c_remove(struct i2c_client *client) +static void cs35l33_i2c_remove(struct i2c_client *client) { struct cs35l33_private *cs35l33 = i2c_get_clientdata(client); @@ -1261,8 +1259,6 @@ static int cs35l33_i2c_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); regulator_bulk_disable(cs35l33->num_core_supplies, cs35l33->core_supplies); - - return 0; } static const struct of_device_id cs35l33_of_match[] = { @@ -1286,7 +1282,7 @@ static struct i2c_driver cs35l33_i2c_driver = { }, .id_table = cs35l33_id, - .probe = cs35l33_i2c_probe, + .probe_new = cs35l33_i2c_probe, .remove = cs35l33_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index ed678241c22b..b3f98023e6a7 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -787,7 +787,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l34_regmap = { @@ -994,8 +993,7 @@ static const char * const cs35l34_core_supplies[] = { "VP", }; -static int cs35l34_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l34_i2c_probe(struct i2c_client *i2c_client) { struct cs35l34_private *cs35l34; struct cs35l34_platform_data *pdata = @@ -1130,7 +1128,7 @@ err_regulator: return ret; } -static int cs35l34_i2c_remove(struct i2c_client *client) +static void cs35l34_i2c_remove(struct i2c_client *client) { struct cs35l34_private *cs35l34 = i2c_get_clientdata(client); @@ -1139,8 +1137,6 @@ static int cs35l34_i2c_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); regulator_bulk_disable(cs35l34->num_core_supplies, cs35l34->core_supplies); - - return 0; } static int __maybe_unused cs35l34_runtime_resume(struct device *dev) @@ -1217,7 +1213,7 @@ static struct i2c_driver cs35l34_i2c_driver = { }, .id_table = cs35l34_id, - .probe = cs35l34_i2c_probe, + .probe_new = cs35l34_i2c_probe, .remove = cs35l34_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 7a5588f1df01..947a440a3a47 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1087,7 +1087,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l35_regmap = { @@ -1311,7 +1310,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); - classh_config->classh_algo_enable = classh ? true : false; + classh_config->classh_algo_enable = (classh != NULL); if (classh_config->classh_algo_enable) { classh_config->classh_bst_override = @@ -1466,8 +1465,7 @@ static const struct reg_sequence cs35l35_errata_patch[] = { { 0x7F, 0x00 }, }; -static int cs35l35_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l35_i2c_probe(struct i2c_client *i2c_client) { struct cs35l35_private *cs35l35; struct device *dev = &i2c_client->dev; @@ -1629,14 +1627,12 @@ err: return ret; } -static int cs35l35_i2c_remove(struct i2c_client *i2c_client) +static void cs35l35_i2c_remove(struct i2c_client *i2c_client) { struct cs35l35_private *cs35l35 = i2c_get_clientdata(i2c_client); regulator_bulk_disable(cs35l35->num_supplies, cs35l35->supplies); gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); - - return 0; } static const struct of_device_id cs35l35_of_match[] = { @@ -1658,7 +1654,7 @@ static struct i2c_driver cs35l35_i2c_driver = { .of_match_table = cs35l35_of_match, }, .id_table = cs35l35_id, - .probe = cs35l35_i2c_probe, + .probe_new = cs35l35_i2c_probe, .remove = cs35l35_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index d83c1b318c1c..31ae752e242f 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -444,7 +444,8 @@ static bool cs35l36_volatile_reg(struct device *dev, unsigned int reg) } } -static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 25, 0); +static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, 0, 912, + TLV_DB_MINMAX_ITEM(-10200, 1200)); static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); static const char * const cs35l36_pcm_sftramp_text[] = { @@ -1299,7 +1300,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs35l36_regmap = { @@ -1700,8 +1700,7 @@ static const struct reg_sequence cs35l36_revb0_errata_patch[] = { { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK2 }, }; -static int cs35l36_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs35l36_i2c_probe(struct i2c_client *i2c_client) { struct cs35l36_private *cs35l36; struct device *dev = &i2c_client->dev; @@ -1804,7 +1803,7 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client, if (ret < 0) { dev_err(&i2c_client->dev, "Failed to read otp_id Register %d\n", ret); - return ret; + goto err; } if ((l37_id_reg & CS35L36_OTP_REV_MASK) == CS35L36_OTP_REV_L37) @@ -1911,7 +1910,7 @@ err_disable_regs: return ret; } -static int cs35l36_i2c_remove(struct i2c_client *client) +static void cs35l36_i2c_remove(struct i2c_client *client) { struct cs35l36_private *cs35l36 = i2c_get_clientdata(client); @@ -1925,8 +1924,6 @@ static int cs35l36_i2c_remove(struct i2c_client *client) gpiod_set_value_cansleep(cs35l36->reset_gpio, 0); regulator_bulk_disable(cs35l36->num_supplies, cs35l36->supplies); - - return 0; } static const struct of_device_id cs35l36_of_match[] = { {.compatible = "cirrus,cs35l36"}, @@ -1947,7 +1944,7 @@ static struct i2c_driver cs35l36_i2c_driver = { .of_match_table = cs35l36_of_match, }, .id_table = cs35l36_id, - .probe = cs35l36_i2c_probe, + .probe_new = cs35l36_i2c_probe, .remove = cs35l36_i2c_remove, }; module_i2c_driver(cs35l36_i2c_driver); diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index d5fa8d2c4a70..3676b596f60b 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -17,38 +17,23 @@ #include <linux/platform_device.h> #include <linux/slab.h> -#include <sound/cs35l41.h> #include "cs35l41.h" -static struct regmap_config cs35l41_regmap_i2c = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = CS35L41_REGSTRIDE, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, - .max_register = CS35L41_LASTREG, - .reg_defaults = cs35l41_reg, - .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), - .volatile_reg = cs35l41_volatile_reg, - .readable_reg = cs35l41_readable_reg, - .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, -}; - static const struct i2c_device_id cs35l41_id_i2c[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, + { "cs35l51", 0 }, + { "cs35l53", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c); -static int cs35l41_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs35l41_i2c_probe(struct i2c_client *client) { struct cs35l41_private *cs35l41; struct device *dev = &client->dev; - struct cs35l41_platform_data *pdata = dev_get_platdata(dev); + struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev); const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; int ret; @@ -68,16 +53,14 @@ static int cs35l41_i2c_probe(struct i2c_client *client, return ret; } - return cs35l41_probe(cs35l41, pdata); + return cs35l41_probe(cs35l41, hw_cfg); } -static int cs35l41_i2c_remove(struct i2c_client *client) +static void cs35l41_i2c_remove(struct i2c_client *client) { struct cs35l41_private *cs35l41 = i2c_get_clientdata(client); cs35l41_remove(cs35l41); - - return 0; } #ifdef CONFIG_OF @@ -100,11 +83,12 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); static struct i2c_driver cs35l41_i2c_driver = { .driver = { .name = "cs35l41", + .pm = &cs35l41_pm_ops, .of_match_table = of_match_ptr(cs35l41_of_match), .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), }, .id_table = cs35l41_id_i2c, - .probe = cs35l41_i2c_probe, + .probe_new = cs35l41_i2c_probe, .remove = cs35l41_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c new file mode 100644 index 000000000000..04be71435491 --- /dev/null +++ b/sound/soc/codecs/cs35l41-lib.c @@ -0,0 +1,1413 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-lib.c -- CS35L41 Common functions for HDA and ASoC Audio drivers +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <david.rhodes@cirrus.com> +// Author: Lucas Tanure <lucas.tanure@cirrus.com> + +#include <linux/dev_printk.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/firmware/cirrus/wmfw.h> + +#include <sound/cs35l41.h> + +static const struct reg_default cs35l41_reg[] = { + { CS35L41_PWR_CTRL1, 0x00000000 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_PWR_CTRL3, 0x01000010 }, + { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, + { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, + { CS35L41_TST_FS_MON0, 0x00020016 }, + { CS35L41_BSTCVRT_COEFF, 0x00002424 }, + { CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 }, + { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A }, + { CS35L41_SP_ENABLES, 0x00000000 }, + { CS35L41_SP_RATE_CTRL, 0x00000028 }, + { CS35L41_SP_FORMAT, 0x18180200 }, + { CS35L41_SP_HIZ_CTRL, 0x00000002 }, + { CS35L41_SP_FRAME_TX_SLOT, 0x03020100 }, + { CS35L41_SP_FRAME_RX_SLOT, 0x00000100 }, + { CS35L41_SP_TX_WL, 0x00000018 }, + { CS35L41_SP_RX_WL, 0x00000018 }, + { CS35L41_DAC_PCM1_SRC, 0x00000008 }, + { CS35L41_ASP_TX1_SRC, 0x00000018 }, + { CS35L41_ASP_TX2_SRC, 0x00000019 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, + { CS35L41_DSP1_RX1_SRC, 0x00000008 }, + { CS35L41_DSP1_RX2_SRC, 0x00000009 }, + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, + { CS35L41_DSP1_RX5_SRC, 0x00000020 }, + { CS35L41_DSP1_RX6_SRC, 0x00000021 }, + { CS35L41_DSP1_RX7_SRC, 0x0000003A }, + { CS35L41_DSP1_RX8_SRC, 0x00000001 }, + { CS35L41_NGATE1_SRC, 0x00000008 }, + { CS35L41_NGATE2_SRC, 0x00000009 }, + { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, + { CS35L41_CLASSH_CFG, 0x000B0405 }, + { CS35L41_WKFET_CFG, 0x00000111 }, + { CS35L41_NG_CFG, 0x00000033 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_IRQ1_MASK1, 0xFFFFFFFF }, + { CS35L41_IRQ1_MASK2, 0xFFFFFFFF }, + { CS35L41_IRQ1_MASK3, 0xFFFF87FF }, + { CS35L41_IRQ1_MASK4, 0xFEFFFFFF }, + { CS35L41_GPIO1_CTRL1, 0xE1000001 }, + { CS35L41_GPIO2_CTRL1, 0xE1000001 }, + { CS35L41_MIXER_NGATE_CFG, 0x00000000 }, + { CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 }, + { CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 }, + { CS35L41_DSP1_CCM_CORE_CTRL, 0x00000101 }, +}; + +static bool cs35l41_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_REVID: + case CS35L41_FABID: + case CS35L41_RELID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_OTP_CTRL0: + case CS35L41_OTP_CTRL3: + case CS35L41_OTP_CTRL4: + case CS35L41_OTP_CTRL5: + case CS35L41_OTP_CTRL6: + case CS35L41_OTP_CTRL7: + case CS35L41_OTP_CTRL8: + case CS35L41_PWR_CTRL1: + case CS35L41_PWR_CTRL2: + case CS35L41_PWR_CTRL3: + case CS35L41_CTRL_OVRRIDE: + case CS35L41_AMP_OUT_MUTE: + case CS35L41_PROTECT_REL_ERR_IGN: + case CS35L41_GPIO_PAD_CONTROL: + case CS35L41_JTAG_CONTROL: + case CS35L41_PWRMGT_CTL: + case CS35L41_WAKESRC_CTL: + case CS35L41_PWRMGT_STS: + case CS35L41_PLL_CLK_CTRL: + case CS35L41_DSP_CLK_CTRL: + case CS35L41_GLOBAL_CLK_CTRL: + case CS35L41_DATA_FS_SEL: + case CS35L41_TST_FS_MON0: + case CS35L41_MDSYNC_EN: + case CS35L41_MDSYNC_TX_ID: + case CS35L41_MDSYNC_PWR_CTRL: + case CS35L41_MDSYNC_DATA_TX: + case CS35L41_MDSYNC_TX_STATUS: + case CS35L41_MDSYNC_DATA_RX: + case CS35L41_MDSYNC_RX_STATUS: + case CS35L41_MDSYNC_ERR_STATUS: + case CS35L41_MDSYNC_SYNC_PTE2: + case CS35L41_MDSYNC_SYNC_PTE3: + case CS35L41_MDSYNC_SYNC_MSM_STATUS: + case CS35L41_BSTCVRT_VCTRL1: + case CS35L41_BSTCVRT_VCTRL2: + case CS35L41_BSTCVRT_PEAK_CUR: + case CS35L41_BSTCVRT_SFT_RAMP: + case CS35L41_BSTCVRT_COEFF: + case CS35L41_BSTCVRT_SLOPE_LBST: + case CS35L41_BSTCVRT_SW_FREQ: + case CS35L41_BSTCVRT_DCM_CTRL: + case CS35L41_BSTCVRT_DCM_MODE_FORCE: + case CS35L41_BSTCVRT_OVERVOLT_CTRL: + case CS35L41_VI_VOL_POL: + case CS35L41_DTEMP_WARN_THLD: + case CS35L41_DTEMP_CFG: + case CS35L41_DTEMP_EN: + case CS35L41_VPVBST_FS_SEL: + case CS35L41_SP_ENABLES: + case CS35L41_SP_RATE_CTRL: + case CS35L41_SP_FORMAT: + case CS35L41_SP_HIZ_CTRL: + case CS35L41_SP_FRAME_TX_SLOT: + case CS35L41_SP_FRAME_RX_SLOT: + case CS35L41_SP_TX_WL: + case CS35L41_SP_RX_WL: + case CS35L41_DAC_PCM1_SRC: + case CS35L41_ASP_TX1_SRC: + case CS35L41_ASP_TX2_SRC: + case CS35L41_ASP_TX3_SRC: + case CS35L41_ASP_TX4_SRC: + case CS35L41_DSP1_RX1_SRC: + case CS35L41_DSP1_RX2_SRC: + case CS35L41_DSP1_RX3_SRC: + case CS35L41_DSP1_RX4_SRC: + case CS35L41_DSP1_RX5_SRC: + case CS35L41_DSP1_RX6_SRC: + case CS35L41_DSP1_RX7_SRC: + case CS35L41_DSP1_RX8_SRC: + case CS35L41_NGATE1_SRC: + case CS35L41_NGATE2_SRC: + case CS35L41_AMP_DIG_VOL_CTRL: + case CS35L41_VPBR_CFG: + case CS35L41_VBBR_CFG: + case CS35L41_VPBR_STATUS: + case CS35L41_VBBR_STATUS: + case CS35L41_OVERTEMP_CFG: + case CS35L41_AMP_ERR_VOL: + case CS35L41_VOL_STATUS_TO_DSP: + case CS35L41_CLASSH_CFG: + case CS35L41_WKFET_CFG: + case CS35L41_NG_CFG: + case CS35L41_AMP_GAIN_CTRL: + case CS35L41_DAC_MSM_CFG: + case CS35L41_IRQ1_CFG: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_MASK1: + case CS35L41_IRQ1_MASK2: + case CS35L41_IRQ1_MASK3: + case CS35L41_IRQ1_MASK4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_CFG: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_MASK1: + case CS35L41_IRQ2_MASK2: + case CS35L41_IRQ2_MASK3: + case CS35L41_IRQ2_MASK4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_GPIO1_CTRL1: + case CS35L41_GPIO2_CTRL1: + case CS35L41_MIXER_NGATE_CFG: + case CS35L41_MIXER_NGATE_CH1_CFG: + case CS35L41_MIXER_NGATE_CH2_CFG: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_CLOCK_DETECT_1: + case CS35L41_DIE_STS1: + case CS35L41_DIE_STS2: + case CS35L41_TEMP_CAL1: + case CS35L41_TEMP_CAL2: + case CS35L41_DSP1_TIMESTAMP_COUNT: + case CS35L41_DSP1_SYS_ID: + case CS35L41_DSP1_SYS_VERSION: + case CS35L41_DSP1_SYS_CORE_ID: + case CS35L41_DSP1_SYS_AHB_ADDR: + case CS35L41_DSP1_SYS_XSRAM_SIZE: + case CS35L41_DSP1_SYS_YSRAM_SIZE: + case CS35L41_DSP1_SYS_PSRAM_SIZE: + case CS35L41_DSP1_SYS_PM_BOOT_SIZE: + case CS35L41_DSP1_SYS_FEATURES: + case CS35L41_DSP1_SYS_FIR_FILTERS: + case CS35L41_DSP1_SYS_LMS_FILTERS: + case CS35L41_DSP1_SYS_XM_BANK_SIZE: + case CS35L41_DSP1_SYS_YM_BANK_SIZE: + case CS35L41_DSP1_SYS_PM_BANK_SIZE: + case CS35L41_DSP1_RX1_RATE: + case CS35L41_DSP1_RX2_RATE: + case CS35L41_DSP1_RX3_RATE: + case CS35L41_DSP1_RX4_RATE: + case CS35L41_DSP1_RX5_RATE: + case CS35L41_DSP1_RX6_RATE: + case CS35L41_DSP1_RX7_RATE: + case CS35L41_DSP1_RX8_RATE: + case CS35L41_DSP1_TX1_RATE: + case CS35L41_DSP1_TX2_RATE: + case CS35L41_DSP1_TX3_RATE: + case CS35L41_DSP1_TX4_RATE: + case CS35L41_DSP1_TX5_RATE: + case CS35L41_DSP1_TX6_RATE: + case CS35L41_DSP1_TX7_RATE: + case CS35L41_DSP1_TX8_RATE: + case CS35L41_DSP1_SCRATCH1: + case CS35L41_DSP1_SCRATCH2: + case CS35L41_DSP1_SCRATCH3: + case CS35L41_DSP1_SCRATCH4: + case CS35L41_DSP1_CCM_CORE_CTRL: + case CS35L41_DSP1_CCM_CLK_OVERRIDE: + case CS35L41_DSP1_XM_MSTR_EN: + case CS35L41_DSP1_XM_CORE_PRI: + case CS35L41_DSP1_XM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_XM_AHB_UP_PL_PRI: + case CS35L41_DSP1_XM_ACCEL_PL0_PRI: + case CS35L41_DSP1_XM_NPL0_PRI: + case CS35L41_DSP1_YM_MSTR_EN: + case CS35L41_DSP1_YM_CORE_PRI: + case CS35L41_DSP1_YM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_YM_AHB_UP_PL_PRI: + case CS35L41_DSP1_YM_ACCEL_PL0_PRI: + case CS35L41_DSP1_YM_NPL0_PRI: + case CS35L41_DSP1_MPU_XM_ACCESS0: + case CS35L41_DSP1_MPU_YM_ACCESS0: + case CS35L41_DSP1_MPU_WNDW_ACCESS0: + case CS35L41_DSP1_MPU_XREG_ACCESS0: + case CS35L41_DSP1_MPU_YREG_ACCESS0: + case CS35L41_DSP1_MPU_XM_ACCESS1: + case CS35L41_DSP1_MPU_YM_ACCESS1: + case CS35L41_DSP1_MPU_WNDW_ACCESS1: + case CS35L41_DSP1_MPU_XREG_ACCESS1: + case CS35L41_DSP1_MPU_YREG_ACCESS1: + case CS35L41_DSP1_MPU_XM_ACCESS2: + case CS35L41_DSP1_MPU_YM_ACCESS2: + case CS35L41_DSP1_MPU_WNDW_ACCESS2: + case CS35L41_DSP1_MPU_XREG_ACCESS2: + case CS35L41_DSP1_MPU_YREG_ACCESS2: + case CS35L41_DSP1_MPU_XM_ACCESS3: + case CS35L41_DSP1_MPU_YM_ACCESS3: + case CS35L41_DSP1_MPU_WNDW_ACCESS3: + case CS35L41_DSP1_MPU_XREG_ACCESS3: + case CS35L41_DSP1_MPU_YREG_ACCESS3: + case CS35L41_DSP1_MPU_XM_VIO_ADDR: + case CS35L41_DSP1_MPU_XM_VIO_STATUS: + case CS35L41_DSP1_MPU_YM_VIO_ADDR: + case CS35L41_DSP1_MPU_YM_VIO_STATUS: + case CS35L41_DSP1_MPU_PM_VIO_ADDR: + case CS35L41_DSP1_MPU_PM_VIO_STATUS: + case CS35L41_DSP1_MPU_LOCK_CONFIG: + case CS35L41_DSP1_MPU_WDT_RST_CTRL: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + /*test regs*/ + case CS35L41_PLL_OVR: + case CS35L41_BST_TEST_DUTY: + case CS35L41_DIGPWM_IOCTRL: + return true; + default: + return false; + } +} + +static bool cs35l41_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_TST_FS_MON0: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + return true; + default: + return false; + } +} + +static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_SFT_RESET: + case CS35L41_FABID: + case CS35L41_REVID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_PWRMGT_CTL: + case CS35L41_WAKESRC_CTL: + case CS35L41_PWRMGT_STS: + case CS35L41_DTEMP_EN: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_GPIO_STATUS1: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + case CS35L41_DSP1_SCRATCH1: + case CS35L41_DSP1_SCRATCH2: + case CS35L41_DSP1_SCRATCH3: + case CS35L41_DSP1_SCRATCH4: + case CS35L41_DSP1_CCM_CLK_OVERRIDE ... CS35L41_DSP1_WDT_STATUS: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +static const struct cs35l41_otp_packed_element_t otp_map_1[] = { + /* addr shift size */ + { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ + { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ + { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ + { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ + { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ + { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ + { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ + { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ + { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ + { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ + { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ + { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ + { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ + { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ + { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ + { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ + { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ + { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ + { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ + { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ + { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ + { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ + { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ + { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ + { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ + { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ + { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ + { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ + { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ + { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ + { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ + { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ + { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ + { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ + { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ + { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ + { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ + { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ + { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ + { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ + { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ + { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ + { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ + { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ + { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ + { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ + { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ + { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ + { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ + { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ + { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ + { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ + { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ + { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ + { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ + { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ + { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ + { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ + { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ + { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ + { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ + { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ + { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ + { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ + { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ + { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ + { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ + { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ + { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ + { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ + { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ + { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ + { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ + { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ + { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ + { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ + { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ + { 0x00007434, 17, 1 }, /*FORCE_CAL*/ + { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ + { 0x00007068, 0, 9 }, /*MODIX*/ + { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ + { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ + { 0x00000000, 0, 1 }, /*extra bit*/ + { 0x00017040, 0, 8 }, /*X_COORDINATE*/ + { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ + { 0x00017040, 16, 8 }, /*WAFER_ID*/ + { 0x00017040, 24, 8 }, /*DVS*/ + { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ +}; + +static const struct cs35l41_otp_packed_element_t otp_map_2[] = { + /* addr shift size */ + { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ + { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ + { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ + { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ + { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ + { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ + { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ + { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ + { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ + { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ + { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ + { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ + { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ + { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ + { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ + { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ + { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ + { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ + { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ + { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ + { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ + { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ + { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ + { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ + { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ + { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ + { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ + { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ + { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ + { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ + { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ + { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ + { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ + { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ + { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ + { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ + { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ + { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ + { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ + { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ + { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ + { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ + { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ + { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ + { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ + { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ + { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ + { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ + { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ + { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ + { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ + { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ + { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ + { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ + { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ + { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ + { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ + { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ + { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ + { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ + { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ + { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ + { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ + { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ + { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ + { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ + { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ + { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ + { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ + { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ + { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ + { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ + { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ + { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ + { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ + { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ + { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ + { 0x00007434, 17, 1 }, /*FORCE_CAL*/ + { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ + { 0x00007068, 0, 9 }, /*MODIX*/ + { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ + { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ + { 0x00004000, 11, 1 }, /*VMON_POL*/ + { 0x00017040, 0, 8 }, /*X_COORDINATE*/ + { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ + { 0x00017040, 16, 8 }, /*WAFER_ID*/ + { 0x00017040, 24, 8 }, /*DVS*/ + { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ +}; + +static const struct reg_sequence cs35l41_reva0_errata_patch[] = { + { 0x00003854, 0x05180240 }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, + { 0x00003014, 0x0200EE0E }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { 0x00000054, 0x00000004 }, + { CS35L41_IRQ1_DB3, 0x00000000 }, + { CS35L41_IRQ2_DB3, 0x00000000 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_revb0_errata_patch[] = { + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_revb2_errata_patch[] = { + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_ASP_TX3_SRC, 0x00000000 }, + { CS35L41_ASP_TX4_SRC, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_fs_errata_patch[] = { + { CS35L41_DSP1_RX1_RATE, 0x00000001 }, + { CS35L41_DSP1_RX2_RATE, 0x00000001 }, + { CS35L41_DSP1_RX3_RATE, 0x00000001 }, + { CS35L41_DSP1_RX4_RATE, 0x00000001 }, + { CS35L41_DSP1_RX5_RATE, 0x00000001 }, + { CS35L41_DSP1_RX6_RATE, 0x00000001 }, + { CS35L41_DSP1_RX7_RATE, 0x00000001 }, + { CS35L41_DSP1_RX8_RATE, 0x00000001 }, + { CS35L41_DSP1_TX1_RATE, 0x00000001 }, + { CS35L41_DSP1_TX2_RATE, 0x00000001 }, + { CS35L41_DSP1_TX3_RATE, 0x00000001 }, + { CS35L41_DSP1_TX4_RATE, 0x00000001 }, + { CS35L41_DSP1_TX5_RATE, 0x00000001 }, + { CS35L41_DSP1_TX6_RATE, 0x00000001 }, + { CS35L41_DSP1_TX7_RATE, 0x00000001 }, + { CS35L41_DSP1_TX8_RATE, 0x00000001 }, +}; + +static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = { + { + .id = 0x01, + .map = otp_map_1, + .num_elements = ARRAY_SIZE(otp_map_1), + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x02, + .map = otp_map_2, + .num_elements = ARRAY_SIZE(otp_map_2), + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x03, + .map = otp_map_2, + .num_elements = ARRAY_SIZE(otp_map_2), + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x06, + .map = otp_map_2, + .num_elements = ARRAY_SIZE(otp_map_2), + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x08, + .map = otp_map_1, + .num_elements = ARRAY_SIZE(otp_map_1), + .bit_offset = 16, + .word_offset = 2, + }, +}; + +struct regmap_config cs35l41_regmap_i2c = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c); + +struct regmap_config cs35l41_regmap_spi = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); + +static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { + if (cs35l41_otp_map_map[i].id == otp_id) + return &cs35l41_otp_map_map[i]; + } + + return NULL; +} + +int cs35l41_test_key_unlock(struct device *dev, struct regmap *regmap) +{ + static const struct reg_sequence unlock[] = { + { CS35L41_TEST_KEY_CTL, 0x00000055 }, + { CS35L41_TEST_KEY_CTL, 0x000000AA }, + }; + int ret; + + ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock)); + if (ret) + dev_err(dev, "Failed to unlock test key: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_test_key_unlock); + +int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap) +{ + static const struct reg_sequence unlock[] = { + { CS35L41_TEST_KEY_CTL, 0x000000CC }, + { CS35L41_TEST_KEY_CTL, 0x00000033 }, + }; + int ret; + + ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock)); + if (ret) + dev_err(dev, "Failed to lock test key: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_test_key_lock); + +/* Must be called with the TEST_KEY unlocked */ +int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap) +{ + const struct cs35l41_otp_map_element_t *otp_map_match; + const struct cs35l41_otp_packed_element_t *otp_map; + int bit_offset, word_offset, ret, i; + unsigned int bit_sum = 8; + u32 otp_val, otp_id_reg; + u32 *otp_mem; + + otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL); + if (!otp_mem) + return -ENOMEM; + + ret = regmap_read(regmap, CS35L41_OTPID, &otp_id_reg); + if (ret) { + dev_err(dev, "Read OTP ID failed: %d\n", ret); + goto err_otp_unpack; + } + + otp_map_match = cs35l41_find_otp_map(otp_id_reg); + + if (!otp_map_match) { + dev_err(dev, "OTP Map matching ID %d not found\n", otp_id_reg); + ret = -EINVAL; + goto err_otp_unpack; + } + + ret = regmap_bulk_read(regmap, CS35L41_OTP_MEM0, otp_mem, CS35L41_OTP_SIZE_WORDS); + if (ret) { + dev_err(dev, "Read OTP Mem failed: %d\n", ret); + goto err_otp_unpack; + } + + otp_map = otp_map_match->map; + + bit_offset = otp_map_match->bit_offset; + word_offset = otp_map_match->word_offset; + + for (i = 0; i < otp_map_match->num_elements; i++) { + dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d, otp_map[i].size = %u\n", + bit_offset, word_offset, bit_sum % 32, otp_map[i].size); + if (bit_offset + otp_map[i].size - 1 >= 32) { + otp_val = (otp_mem[word_offset] & + GENMASK(31, bit_offset)) >> bit_offset; + otp_val |= (otp_mem[++word_offset] & + GENMASK(bit_offset + otp_map[i].size - 33, 0)) << + (32 - bit_offset); + bit_offset += otp_map[i].size - 32; + } else if (bit_offset + otp_map[i].size - 1 >= 0) { + otp_val = (otp_mem[word_offset] & + GENMASK(bit_offset + otp_map[i].size - 1, bit_offset) + ) >> bit_offset; + bit_offset += otp_map[i].size; + } else /* both bit_offset and otp_map[i].size are 0 */ + otp_val = 0; + + bit_sum += otp_map[i].size; + + if (bit_offset == 32) { + bit_offset = 0; + word_offset++; + } + + if (otp_map[i].reg != 0) { + ret = regmap_update_bits(regmap, otp_map[i].reg, + GENMASK(otp_map[i].shift + otp_map[i].size - 1, + otp_map[i].shift), + otp_val << otp_map[i].shift); + if (ret < 0) { + dev_err(dev, "Write OTP val failed: %d\n", ret); + goto err_otp_unpack; + } + } + } + + ret = 0; + +err_otp_unpack: + kfree(otp_mem); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_otp_unpack); + +/* Must be called with the TEST_KEY unlocked */ +int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid) +{ + char *rev; + int ret; + + switch (reg_revid) { + case CS35L41_REVID_A0: + ret = regmap_register_patch(reg, cs35l41_reva0_errata_patch, + ARRAY_SIZE(cs35l41_reva0_errata_patch)); + rev = "A0"; + break; + case CS35L41_REVID_B0: + ret = regmap_register_patch(reg, cs35l41_revb0_errata_patch, + ARRAY_SIZE(cs35l41_revb0_errata_patch)); + rev = "B0"; + break; + case CS35L41_REVID_B2: + ret = regmap_register_patch(reg, cs35l41_revb2_errata_patch, + ARRAY_SIZE(cs35l41_revb2_errata_patch)); + rev = "B2"; + break; + default: + ret = -EINVAL; + rev = "XX"; + break; + } + + if (ret) + dev_err(dev, "Failed to apply %s errata patch: %d\n", rev, ret); + + ret = regmap_write(reg, CS35L41_DSP1_CCM_CORE_CTRL, 0); + if (ret < 0) + dev_err(dev, "Write CCM_CORE_CTRL failed: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch); + +int cs35l41_set_channels(struct device *dev, struct regmap *reg, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + unsigned int val, mask; + int i; + + if (tx_num > 4 || rx_num > 2) + return -EINVAL; + + val = 0; + mask = 0; + for (i = 0; i < rx_num; i++) { + dev_dbg(dev, "rx slot %d position = %d\n", i, rx_slot[i]); + val |= rx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(reg, CS35L41_SP_FRAME_RX_SLOT, mask, val); + + val = 0; + mask = 0; + for (i = 0; i < tx_num; i++) { + dev_dbg(dev, "tx slot %d position = %d\n", i, tx_slot[i]); + val |= tx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(reg, CS35L41_SP_FRAME_TX_SLOT, mask, val); + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_set_channels); + +static const unsigned char cs35l41_bst_k1_table[4][5] = { + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 } +}; + +static const unsigned char cs35l41_bst_k2_table[4][5] = { + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA } +}; + +static const unsigned char cs35l41_bst_slope_table[4] = { + 0x75, 0x6B, 0x3B, 0x28 +}; + +static int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, + int boost_cap, int boost_ipk) +{ + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; + int ret; + + switch (boost_ind) { + case 1000: /* 1.0 uH */ + bst_lbst_val = 0; + break; + case 1200: /* 1.2 uH */ + bst_lbst_val = 1; + break; + case 1500: /* 1.5 uH */ + bst_lbst_val = 2; + break; + case 2200: /* 2.2 uH */ + bst_lbst_val = 3; + break; + default: + dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind); + return -EINVAL; + } + + switch (boost_cap) { + case 0 ... 19: + bst_cbst_range = 0; + break; + case 20 ... 50: + bst_cbst_range = 1; + break; + case 51 ... 100: + bst_cbst_range = 2; + break; + case 101 ... 200: + bst_cbst_range = 3; + break; + default: + if (boost_cap < 0) { + dev_err(dev, "Invalid boost capacitor value: %d nH\n", boost_cap); + return -EINVAL; + } + /* 201 uF and greater */ + bst_cbst_range = 4; + } + + if (boost_ipk < 1600 || boost_ipk > 4500) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk); + return -EINVAL; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K1_SHIFT | + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K2_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost coefficients: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK, + cs35l41_bst_slope_table[bst_lbst_val] + << CS35L41_BST_SLOPE_SHIFT | + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret); + return ret; + } + + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK, + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret); + return ret; + } + + regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT); + + return 0; +} + +static const struct reg_sequence cs35l41_safe_to_reset[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x0000393C, 0x000000C0, 6000}, + { 0x0000393C, 0x00000000 }, + { 0x00007414, 0x00C82222 }, + { 0x0000742C, 0x00000000 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_active_to_safe[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00007438, 0x00585941 }, + { CS35L41_PWR_CTRL1, 0x00000000 }, + { 0x0000742C, 0x00000009, 3000 }, + { 0x00007438, 0x00580941 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_safe_to_active[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x0000742C, 0x0000000F }, + { 0x0000742C, 0x00000079 }, + { 0x00007438, 0x00585941 }, + { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1 + { 0x0000742C, 0x000000F9 }, + { 0x00007438, 0x00580941 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_reset_to_safe[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00007438, 0x00585941 }, + { 0x00007414, 0x08C82222 }, + { 0x0000742C, 0x00000009 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +int cs35l41_init_boost(struct device *dev, struct regmap *regmap, + struct cs35l41_hw_cfg *hw_cfg) +{ + int ret; + + switch (hw_cfg->bst_type) { + case CS35L41_INT_BOOST: + ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind, + hw_cfg->bst_cap, hw_cfg->bst_ipk); + if (ret) + dev_err(dev, "Error in Boost DT config: %d\n", ret); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + /* Only CLSA0100 doesn't use GPIO as VSPK switch, but even on that laptop we can + * toggle GPIO1 as is not connected to anything. + * There will be no other device without VSPK switch. + */ + regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001); + regmap_multi_reg_write(regmap, cs35l41_reset_to_safe, + ARRAY_SIZE(cs35l41_reset_to_safe)); + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, + CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT); + break; + default: + dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type); + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_init_boost); + +bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type) +{ + switch (b_type) { + /* There is only one laptop that doesn't have VSPK switch. */ + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + return false; + case CS35L41_EXT_BOOST: + regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001); + regmap_multi_reg_write(regmap, cs35l41_safe_to_reset, + ARRAY_SIZE(cs35l41_safe_to_reset)); + return true; + default: + return true; + } +} +EXPORT_SYMBOL_GPL(cs35l41_safe_reset); + +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable) +{ + int ret; + + switch (b_type) { + case CS35L41_INT_BOOST: + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, + enable << CS35L41_GLOBAL_EN_SHIFT); + usleep_range(3000, 3100); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: + if (enable) + ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active, + ARRAY_SIZE(cs35l41_safe_to_active)); + else + ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe, + ARRAY_SIZE(cs35l41_active_to_safe)); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_global_enable); + +int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg) +{ + struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1; + struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2; + int irq_pol = IRQF_TRIGGER_NONE; + + regmap_update_bits(regmap, CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + gpio1->pol_inv << CS35L41_GPIO_POL_SHIFT | + !gpio1->out_en << CS35L41_GPIO_DIR_SHIFT); + + regmap_update_bits(regmap, CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + gpio2->pol_inv << CS35L41_GPIO_POL_SHIFT | + !gpio2->out_en << CS35L41_GPIO_DIR_SHIFT); + + if (gpio1->valid) + regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO1_CTRL_MASK, + gpio1->func << CS35L41_GPIO1_CTRL_SHIFT); + + if (gpio2->valid) { + regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO2_CTRL_MASK, + gpio2->func << CS35L41_GPIO2_CTRL_SHIFT); + + switch (gpio2->func) { + case CS35L41_GPIO2_INT_PUSH_PULL_LOW: + case CS35L41_GPIO2_INT_OPEN_DRAIN: + irq_pol = IRQF_TRIGGER_LOW; + break; + case CS35L41_GPIO2_INT_PUSH_PULL_HIGH: + irq_pol = IRQF_TRIGGER_HIGH; + break; + default: + break; + } + } + + return irq_pol; +} +EXPORT_SYMBOL_GPL(cs35l41_gpio_config); + +static const struct cs_dsp_region cs35l41_dsp1_regions[] = { + { .type = WMFW_HALO_PM_PACKED, .base = CS35L41_DSP1_PMEM_0 }, + { .type = WMFW_HALO_XM_PACKED, .base = CS35L41_DSP1_XMEM_PACK_0 }, + { .type = WMFW_HALO_YM_PACKED, .base = CS35L41_DSP1_YMEM_PACK_0 }, + {. type = WMFW_ADSP2_XM, .base = CS35L41_DSP1_XMEM_UNPACK24_0}, + {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, +}; + +void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp) +{ + dsp->num = 1; + dsp->type = WMFW_HALO; + dsp->rev = 0; + dsp->dev = dev; + dsp->regmap = reg; + dsp->base = CS35L41_DSP1_CTRL_BASE; + dsp->base_sysinfo = CS35L41_DSP1_SYS_ID; + dsp->mem = cs35l41_dsp1_regions; + dsp->num_mems = ARRAY_SIZE(cs35l41_dsp1_regions); + dsp->lock_regions = 0xFFFFFFFF; +} +EXPORT_SYMBOL_GPL(cs35l41_configure_cs_dsp); + +static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, + enum cs35l41_cspl_mbox_status sts) +{ + switch (cmd) { + case CSPL_MBOX_CMD_NONE: + case CSPL_MBOX_CMD_UNKNOWN_CMD: + return true; + case CSPL_MBOX_CMD_PAUSE: + case CSPL_MBOX_CMD_OUT_OF_HIBERNATE: + return (sts == CSPL_MBOX_STS_PAUSED); + case CSPL_MBOX_CMD_RESUME: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_REINIT: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_STOP_PRE_REINIT: + return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); + default: + return false; + } +} + +int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, + enum cs35l41_cspl_mbox_cmd cmd) +{ + unsigned int sts = 0, i; + int ret; + + // Set mailbox cmd + ret = regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd); + if (ret < 0) { + if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) + dev_err(dev, "Failed to write MBOX: %d\n", ret); + return ret; + } + + // Read mailbox status and verify it is appropriate for the given cmd + for (i = 0; i < 5; i++) { + usleep_range(1000, 1100); + + ret = regmap_read(regmap, CS35L41_DSP_MBOX_2, &sts); + if (ret < 0) { + dev_err(dev, "Failed to read MBOX STS: %d\n", ret); + continue; + } + + if (!cs35l41_check_cspl_mbox_sts(cmd, sts)) + dev_dbg(dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts); + else + return 0; + } + + if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE) + dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts); + + return -ENOMSG; +} +EXPORT_SYMBOL_GPL(cs35l41_set_cspl_mbox_cmd); + +int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap) +{ + int ret; + + ret = regmap_multi_reg_write(regmap, cs35l41_fs_errata_patch, + ARRAY_SIZE(cs35l41_fs_errata_patch)); + if (ret < 0) + dev_err(dev, "Failed to write fs errata: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata); + +int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap, + enum cs35l41_boost_type b_type) +{ + if (!cs35l41_safe_reset(regmap, b_type)) { + dev_dbg(dev, "System does not support Suspend\n"); + return -EINVAL; + } + + dev_dbg(dev, "Enter hibernate\n"); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + // Don't wait for ACK since bus activity would wake the device + regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate); + +static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap) +{ + const int pwrmgt_retries = 10; + unsigned int sts; + int i, ret; + + for (i = 0; i < pwrmgt_retries; i++) { + ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts); + if (ret) + dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret); + else if (!(sts & CS35L41_WR_PEND_STS_MASK)) + return; + + udelay(20); + } + + dev_err(dev, "Timed out reading PWRMGT_STS\n"); +} + +int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap) +{ + const int wake_retries = 20; + const int sleep_retries = 5; + int ret, i, j; + + for (i = 0; i < sleep_retries; i++) { + dev_dbg(dev, "Exit hibernate\n"); + + for (j = 0; j < wake_retries; j++) { + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, + CSPL_MBOX_CMD_OUT_OF_HIBERNATE); + if (!ret) + break; + + usleep_range(100, 200); + } + + if (j < wake_retries) { + dev_dbg(dev, "Wake success at cycle: %d\n", j); + return 0; + } + + dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3); + } + + dev_err(dev, "Timed out waking device\n"); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate); + +MODULE_DESCRIPTION("CS35L41 library"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); +MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index 3fa99741779a..5c8bb24909eb 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -15,28 +15,13 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> -#include <sound/cs35l41.h> #include "cs35l41.h" -static struct regmap_config cs35l41_regmap_spi = { - .reg_bits = 32, - .val_bits = 32, - .pad_bits = 16, - .reg_stride = CS35L41_REGSTRIDE, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, - .max_register = CS35L41_LASTREG, - .reg_defaults = cs35l41_reg, - .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), - .volatile_reg = cs35l41_volatile_reg, - .readable_reg = cs35l41_readable_reg, - .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, -}; - static const struct spi_device_id cs35l41_id_spi[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, + { "cs35l51", 0 }, + { "cs35l53", 0 }, {} }; @@ -45,7 +30,7 @@ MODULE_DEVICE_TABLE(spi, cs35l41_id_spi); static int cs35l41_spi_probe(struct spi_device *spi) { const struct regmap_config *regmap_config = &cs35l41_regmap_spi; - struct cs35l41_platform_data *pdata = dev_get_platdata(&spi->dev); + struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev); struct cs35l41_private *cs35l41; int ret; @@ -67,16 +52,14 @@ static int cs35l41_spi_probe(struct spi_device *spi) cs35l41->dev = &spi->dev; cs35l41->irq = spi->irq; - return cs35l41_probe(cs35l41, pdata); + return cs35l41_probe(cs35l41, hw_cfg); } -static int cs35l41_spi_remove(struct spi_device *spi) +static void cs35l41_spi_remove(struct spi_device *spi) { struct cs35l41_private *cs35l41 = spi_get_drvdata(spi); cs35l41_remove(cs35l41); - - return 0; } #ifdef CONFIG_OF @@ -91,6 +74,7 @@ MODULE_DEVICE_TABLE(of, cs35l41_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id cs35l41_acpi_match[] = { { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + { "CLSA3541", 0 }, /* Cirrus Logic PnP ID + part ID */ {}, }; MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); @@ -99,6 +83,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); static struct spi_driver cs35l41_spi_driver = { .driver = { .name = "cs35l41", + .pm = &cs35l41_pm_ops, .of_match_table = of_match_ptr(cs35l41_of_match), .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), }, diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c deleted file mode 100644 index 964e530afa27..000000000000 --- a/sound/soc/codecs/cs35l41-tables.c +++ /dev/null @@ -1,594 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// cs35l41-tables.c -- CS35L41 ALSA SoC audio driver -// -// Copyright 2017-2021 Cirrus Logic, Inc. -// -// Author: David Rhodes <david.rhodes@cirrus.com> - -#include "cs35l41.h" - -const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { - { CS35L41_PWR_CTRL1, 0x00000000 }, - { CS35L41_PWR_CTRL3, 0x01000010 }, - { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, - { CS35L41_SP_ENABLES, 0x00000000 }, - { CS35L41_SP_RATE_CTRL, 0x00000028 }, - { CS35L41_SP_FORMAT, 0x18180200 }, - { CS35L41_SP_HIZ_CTRL, 0x00000002 }, - { CS35L41_SP_FRAME_TX_SLOT, 0x03020100 }, - { CS35L41_SP_FRAME_RX_SLOT, 0x00000100 }, - { CS35L41_SP_TX_WL, 0x00000018 }, - { CS35L41_SP_RX_WL, 0x00000018 }, - { CS35L41_DAC_PCM1_SRC, 0x00000008 }, - { CS35L41_ASP_TX1_SRC, 0x00000018 }, - { CS35L41_ASP_TX2_SRC, 0x00000019 }, - { CS35L41_ASP_TX3_SRC, 0x00000020 }, - { CS35L41_ASP_TX4_SRC, 0x00000021 }, - { CS35L41_DSP1_RX1_SRC, 0x00000008 }, - { CS35L41_DSP1_RX2_SRC, 0x00000009 }, - { CS35L41_DSP1_RX3_SRC, 0x00000018 }, - { CS35L41_DSP1_RX4_SRC, 0x00000019 }, - { CS35L41_DSP1_RX5_SRC, 0x00000020 }, - { CS35L41_DSP1_RX6_SRC, 0x00000021 }, - { CS35L41_DSP1_RX7_SRC, 0x0000003A }, - { CS35L41_DSP1_RX8_SRC, 0x00000001 }, - { CS35L41_NGATE1_SRC, 0x00000008 }, - { CS35L41_NGATE2_SRC, 0x00000009 }, - { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, - { CS35L41_CLASSH_CFG, 0x000B0405 }, - { CS35L41_WKFET_CFG, 0x00000111 }, - { CS35L41_NG_CFG, 0x00000033 }, - { CS35L41_AMP_GAIN_CTRL, 0x00000273 }, - { CS35L41_GPIO1_CTRL1, 0xE1000001 }, - { CS35L41_GPIO2_CTRL1, 0xE1000001 }, - { CS35L41_MIXER_NGATE_CFG, 0x00000000 }, - { CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 }, - { CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 }, -}; - -bool cs35l41_readable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CS35L41_DEVID: - case CS35L41_REVID: - case CS35L41_FABID: - case CS35L41_RELID: - case CS35L41_OTPID: - case CS35L41_TEST_KEY_CTL: - case CS35L41_USER_KEY_CTL: - case CS35L41_OTP_CTRL0: - case CS35L41_OTP_CTRL3: - case CS35L41_OTP_CTRL4: - case CS35L41_OTP_CTRL5: - case CS35L41_OTP_CTRL6: - case CS35L41_OTP_CTRL7: - case CS35L41_OTP_CTRL8: - case CS35L41_PWR_CTRL1: - case CS35L41_PWR_CTRL2: - case CS35L41_PWR_CTRL3: - case CS35L41_CTRL_OVRRIDE: - case CS35L41_AMP_OUT_MUTE: - case CS35L41_PROTECT_REL_ERR_IGN: - case CS35L41_GPIO_PAD_CONTROL: - case CS35L41_JTAG_CONTROL: - case CS35L41_PLL_CLK_CTRL: - case CS35L41_DSP_CLK_CTRL: - case CS35L41_GLOBAL_CLK_CTRL: - case CS35L41_DATA_FS_SEL: - case CS35L41_MDSYNC_EN: - case CS35L41_MDSYNC_TX_ID: - case CS35L41_MDSYNC_PWR_CTRL: - case CS35L41_MDSYNC_DATA_TX: - case CS35L41_MDSYNC_TX_STATUS: - case CS35L41_MDSYNC_DATA_RX: - case CS35L41_MDSYNC_RX_STATUS: - case CS35L41_MDSYNC_ERR_STATUS: - case CS35L41_MDSYNC_SYNC_PTE2: - case CS35L41_MDSYNC_SYNC_PTE3: - case CS35L41_MDSYNC_SYNC_MSM_STATUS: - case CS35L41_BSTCVRT_VCTRL1: - case CS35L41_BSTCVRT_VCTRL2: - case CS35L41_BSTCVRT_PEAK_CUR: - case CS35L41_BSTCVRT_SFT_RAMP: - case CS35L41_BSTCVRT_COEFF: - case CS35L41_BSTCVRT_SLOPE_LBST: - case CS35L41_BSTCVRT_SW_FREQ: - case CS35L41_BSTCVRT_DCM_CTRL: - case CS35L41_BSTCVRT_DCM_MODE_FORCE: - case CS35L41_BSTCVRT_OVERVOLT_CTRL: - case CS35L41_VI_VOL_POL: - case CS35L41_DTEMP_WARN_THLD: - case CS35L41_DTEMP_CFG: - case CS35L41_DTEMP_EN: - case CS35L41_VPVBST_FS_SEL: - case CS35L41_SP_ENABLES: - case CS35L41_SP_RATE_CTRL: - case CS35L41_SP_FORMAT: - case CS35L41_SP_HIZ_CTRL: - case CS35L41_SP_FRAME_TX_SLOT: - case CS35L41_SP_FRAME_RX_SLOT: - case CS35L41_SP_TX_WL: - case CS35L41_SP_RX_WL: - case CS35L41_DAC_PCM1_SRC: - case CS35L41_ASP_TX1_SRC: - case CS35L41_ASP_TX2_SRC: - case CS35L41_ASP_TX3_SRC: - case CS35L41_ASP_TX4_SRC: - case CS35L41_DSP1_RX1_SRC: - case CS35L41_DSP1_RX2_SRC: - case CS35L41_DSP1_RX3_SRC: - case CS35L41_DSP1_RX4_SRC: - case CS35L41_DSP1_RX5_SRC: - case CS35L41_DSP1_RX6_SRC: - case CS35L41_DSP1_RX7_SRC: - case CS35L41_DSP1_RX8_SRC: - case CS35L41_NGATE1_SRC: - case CS35L41_NGATE2_SRC: - case CS35L41_AMP_DIG_VOL_CTRL: - case CS35L41_VPBR_CFG: - case CS35L41_VBBR_CFG: - case CS35L41_VPBR_STATUS: - case CS35L41_VBBR_STATUS: - case CS35L41_OVERTEMP_CFG: - case CS35L41_AMP_ERR_VOL: - case CS35L41_VOL_STATUS_TO_DSP: - case CS35L41_CLASSH_CFG: - case CS35L41_WKFET_CFG: - case CS35L41_NG_CFG: - case CS35L41_AMP_GAIN_CTRL: - case CS35L41_DAC_MSM_CFG: - case CS35L41_IRQ1_CFG: - case CS35L41_IRQ1_STATUS: - case CS35L41_IRQ1_STATUS1: - case CS35L41_IRQ1_STATUS2: - case CS35L41_IRQ1_STATUS3: - case CS35L41_IRQ1_STATUS4: - case CS35L41_IRQ1_RAW_STATUS1: - case CS35L41_IRQ1_RAW_STATUS2: - case CS35L41_IRQ1_RAW_STATUS3: - case CS35L41_IRQ1_RAW_STATUS4: - case CS35L41_IRQ1_MASK1: - case CS35L41_IRQ1_MASK2: - case CS35L41_IRQ1_MASK3: - case CS35L41_IRQ1_MASK4: - case CS35L41_IRQ1_FRC1: - case CS35L41_IRQ1_FRC2: - case CS35L41_IRQ1_FRC3: - case CS35L41_IRQ1_FRC4: - case CS35L41_IRQ1_EDGE1: - case CS35L41_IRQ1_EDGE4: - case CS35L41_IRQ1_POL1: - case CS35L41_IRQ1_POL2: - case CS35L41_IRQ1_POL3: - case CS35L41_IRQ1_POL4: - case CS35L41_IRQ1_DB3: - case CS35L41_IRQ2_CFG: - case CS35L41_IRQ2_STATUS: - case CS35L41_IRQ2_STATUS1: - case CS35L41_IRQ2_STATUS2: - case CS35L41_IRQ2_STATUS3: - case CS35L41_IRQ2_STATUS4: - case CS35L41_IRQ2_RAW_STATUS1: - case CS35L41_IRQ2_RAW_STATUS2: - case CS35L41_IRQ2_RAW_STATUS3: - case CS35L41_IRQ2_RAW_STATUS4: - case CS35L41_IRQ2_MASK1: - case CS35L41_IRQ2_MASK2: - case CS35L41_IRQ2_MASK3: - case CS35L41_IRQ2_MASK4: - case CS35L41_IRQ2_FRC1: - case CS35L41_IRQ2_FRC2: - case CS35L41_IRQ2_FRC3: - case CS35L41_IRQ2_FRC4: - case CS35L41_IRQ2_EDGE1: - case CS35L41_IRQ2_EDGE4: - case CS35L41_IRQ2_POL1: - case CS35L41_IRQ2_POL2: - case CS35L41_IRQ2_POL3: - case CS35L41_IRQ2_POL4: - case CS35L41_IRQ2_DB3: - case CS35L41_GPIO_STATUS1: - case CS35L41_GPIO1_CTRL1: - case CS35L41_GPIO2_CTRL1: - case CS35L41_MIXER_NGATE_CFG: - case CS35L41_MIXER_NGATE_CH1_CFG: - case CS35L41_MIXER_NGATE_CH2_CFG: - case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: - case CS35L41_CLOCK_DETECT_1: - case CS35L41_DIE_STS1: - case CS35L41_DIE_STS2: - case CS35L41_TEMP_CAL1: - case CS35L41_TEMP_CAL2: - case CS35L41_OTP_TRIM_1: - case CS35L41_OTP_TRIM_2: - case CS35L41_OTP_TRIM_3: - case CS35L41_OTP_TRIM_4: - case CS35L41_OTP_TRIM_5: - case CS35L41_OTP_TRIM_6: - case CS35L41_OTP_TRIM_7: - case CS35L41_OTP_TRIM_8: - case CS35L41_OTP_TRIM_9: - case CS35L41_OTP_TRIM_10: - case CS35L41_OTP_TRIM_11: - case CS35L41_OTP_TRIM_12: - case CS35L41_OTP_TRIM_13: - case CS35L41_OTP_TRIM_14: - case CS35L41_OTP_TRIM_15: - case CS35L41_OTP_TRIM_16: - case CS35L41_OTP_TRIM_17: - case CS35L41_OTP_TRIM_18: - case CS35L41_OTP_TRIM_19: - case CS35L41_OTP_TRIM_20: - case CS35L41_OTP_TRIM_21: - case CS35L41_OTP_TRIM_22: - case CS35L41_OTP_TRIM_23: - case CS35L41_OTP_TRIM_24: - case CS35L41_OTP_TRIM_25: - case CS35L41_OTP_TRIM_26: - case CS35L41_OTP_TRIM_27: - case CS35L41_OTP_TRIM_28: - case CS35L41_OTP_TRIM_29: - case CS35L41_OTP_TRIM_30: - case CS35L41_OTP_TRIM_31: - case CS35L41_OTP_TRIM_32: - case CS35L41_OTP_TRIM_33: - case CS35L41_OTP_TRIM_34: - case CS35L41_OTP_TRIM_35: - case CS35L41_OTP_TRIM_36: - case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: - /*test regs*/ - case CS35L41_PLL_OVR: - case CS35L41_BST_TEST_DUTY: - case CS35L41_DIGPWM_IOCTRL: - return true; - default: - return false; - } -} - -bool cs35l41_precious_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: - return true; - default: - return false; - } -} - -bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CS35L41_DEVID: - case CS35L41_SFT_RESET: - case CS35L41_FABID: - case CS35L41_REVID: - case CS35L41_DTEMP_EN: - case CS35L41_IRQ1_STATUS: - case CS35L41_IRQ1_STATUS1: - case CS35L41_IRQ1_STATUS2: - case CS35L41_IRQ1_STATUS3: - case CS35L41_IRQ1_STATUS4: - case CS35L41_IRQ1_RAW_STATUS1: - case CS35L41_IRQ1_RAW_STATUS2: - case CS35L41_IRQ1_RAW_STATUS3: - case CS35L41_IRQ1_RAW_STATUS4: - case CS35L41_IRQ1_FRC1: - case CS35L41_IRQ1_FRC2: - case CS35L41_IRQ1_FRC3: - case CS35L41_IRQ1_FRC4: - case CS35L41_IRQ1_EDGE1: - case CS35L41_IRQ1_EDGE4: - case CS35L41_IRQ1_POL1: - case CS35L41_IRQ1_POL2: - case CS35L41_IRQ1_POL3: - case CS35L41_IRQ1_POL4: - case CS35L41_IRQ1_DB3: - case CS35L41_IRQ2_STATUS: - case CS35L41_IRQ2_STATUS1: - case CS35L41_IRQ2_STATUS2: - case CS35L41_IRQ2_STATUS3: - case CS35L41_IRQ2_STATUS4: - case CS35L41_IRQ2_RAW_STATUS1: - case CS35L41_IRQ2_RAW_STATUS2: - case CS35L41_IRQ2_RAW_STATUS3: - case CS35L41_IRQ2_RAW_STATUS4: - case CS35L41_IRQ2_FRC1: - case CS35L41_IRQ2_FRC2: - case CS35L41_IRQ2_FRC3: - case CS35L41_IRQ2_FRC4: - case CS35L41_IRQ2_EDGE1: - case CS35L41_IRQ2_EDGE4: - case CS35L41_IRQ2_POL1: - case CS35L41_IRQ2_POL2: - case CS35L41_IRQ2_POL3: - case CS35L41_IRQ2_POL4: - case CS35L41_IRQ2_DB3: - case CS35L41_GPIO_STATUS1: - case CS35L41_OTP_TRIM_1: - case CS35L41_OTP_TRIM_2: - case CS35L41_OTP_TRIM_3: - case CS35L41_OTP_TRIM_4: - case CS35L41_OTP_TRIM_5: - case CS35L41_OTP_TRIM_6: - case CS35L41_OTP_TRIM_7: - case CS35L41_OTP_TRIM_8: - case CS35L41_OTP_TRIM_9: - case CS35L41_OTP_TRIM_10: - case CS35L41_OTP_TRIM_11: - case CS35L41_OTP_TRIM_12: - case CS35L41_OTP_TRIM_13: - case CS35L41_OTP_TRIM_14: - case CS35L41_OTP_TRIM_15: - case CS35L41_OTP_TRIM_16: - case CS35L41_OTP_TRIM_17: - case CS35L41_OTP_TRIM_18: - case CS35L41_OTP_TRIM_19: - case CS35L41_OTP_TRIM_20: - case CS35L41_OTP_TRIM_21: - case CS35L41_OTP_TRIM_22: - case CS35L41_OTP_TRIM_23: - case CS35L41_OTP_TRIM_24: - case CS35L41_OTP_TRIM_25: - case CS35L41_OTP_TRIM_26: - case CS35L41_OTP_TRIM_27: - case CS35L41_OTP_TRIM_28: - case CS35L41_OTP_TRIM_29: - case CS35L41_OTP_TRIM_30: - case CS35L41_OTP_TRIM_31: - case CS35L41_OTP_TRIM_32: - case CS35L41_OTP_TRIM_33: - case CS35L41_OTP_TRIM_34: - case CS35L41_OTP_TRIM_35: - case CS35L41_OTP_TRIM_36: - case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: - return true; - default: - return false; - } -} - -static const struct cs35l41_otp_packed_element_t otp_map_1[CS35L41_NUM_OTP_ELEM] = { - /* addr shift size */ - { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ - { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ - { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ - { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ - { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ - { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ - { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ - { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ - { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ - { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ - { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ - { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ - { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ - { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ - { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ - { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ - { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ - { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ - { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ - { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ - { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ - { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ - { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ - { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ - { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ - { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ - { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ - { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ - { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ - { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ - { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ - { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ - { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ - { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ - { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ - { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ - { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ - { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ - { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ - { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ - { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ - { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ - { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ - { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ - { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ - { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ - { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ - { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ - { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ - { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ - { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ - { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ - { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ - { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ - { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ - { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ - { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ - { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ - { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ - { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ - { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ - { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ - { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ - { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ - { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ - { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ - { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ - { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ - { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ - { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ - { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ - { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ - { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ - { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ - { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ - { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ - { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ - { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ - { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ - { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ - { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ - { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ - { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ - { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ - { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ - { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ - { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ - { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ - { 0x00007434, 17, 1 }, /*FORCE_CAL*/ - { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ - { 0x00007068, 0, 9 }, /*MODIX*/ - { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ - { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ - { 0x00000000, 0, 1 }, /*extra bit*/ - { 0x00017040, 0, 8 }, /*X_COORDINATE*/ - { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ - { 0x00017040, 16, 8 }, /*WAFER_ID*/ - { 0x00017040, 24, 8 }, /*DVS*/ - { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ -}; - -static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] = { - /* addr shift size */ - { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ - { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ - { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ - { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ - { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ - { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ - { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ - { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ - { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ - { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ - { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ - { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ - { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ - { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ - { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ - { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ - { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ - { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ - { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ - { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ - { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ - { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ - { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ - { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ - { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ - { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ - { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ - { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ - { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ - { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ - { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ - { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ - { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ - { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ - { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ - { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ - { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ - { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ - { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ - { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ - { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ - { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ - { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ - { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ - { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ - { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ - { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ - { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ - { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ - { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ - { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ - { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ - { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ - { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ - { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ - { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ - { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ - { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ - { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ - { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ - { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ - { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ - { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ - { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ - { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ - { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ - { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ - { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ - { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ - { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ - { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ - { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ - { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ - { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ - { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ - { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ - { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ - { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ - { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ - { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ - { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ - { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ - { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ - { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ - { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ - { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ - { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ - { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ - { 0x00007434, 17, 1 }, /*FORCE_CAL*/ - { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ - { 0x00007068, 0, 9 }, /*MODIX*/ - { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ - { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ - { 0x00004000, 11, 1 }, /*VMON_POL*/ - { 0x00017040, 0, 8 }, /*X_COORDINATE*/ - { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ - { 0x00017040, 16, 8 }, /*WAFER_ID*/ - { 0x00017040, 24, 8 }, /*DVS*/ - { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ -}; - -const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = { - { - .id = 0x01, - .map = otp_map_1, - .num_elements = CS35L41_NUM_OTP_ELEM, - .bit_offset = 16, - .word_offset = 2, - }, - { - .id = 0x02, - .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, - .bit_offset = 16, - .word_offset = 2, - }, - { - .id = 0x03, - .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, - .bit_offset = 16, - .word_offset = 2, - }, - { - .id = 0x06, - .map = otp_map_2, - .num_elements = CS35L41_NUM_OTP_ELEM, - .bit_offset = 16, - .word_offset = 2, - }, - { - .id = 0x08, - .map = otp_map_1, - .num_elements = CS35L41_NUM_OTP_ELEM, - .bit_offset = 16, - .word_offset = 2, - }, -}; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 9c4d481f7614..c223d83e02cf 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -6,6 +6,7 @@ // // Author: David Rhodes <david.rhodes@cirrus.com> +#include <linux/acpi.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/init.h> @@ -13,8 +14,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/of_device.h> +#include <linux/pm_runtime.h> #include <linux/property.h> -#include <linux/slab.h> #include <sound/initval.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -151,24 +152,6 @@ static const struct cs35l41_fs_mon_config cs35l41_fs_mon[] = { { 6144000, 16, 24 }, }; -static const unsigned char cs35l41_bst_k1_table[4][5] = { - { 0x24, 0x32, 0x32, 0x4F, 0x57 }, - { 0x24, 0x32, 0x32, 0x4F, 0x57 }, - { 0x40, 0x32, 0x32, 0x4F, 0x57 }, - { 0x40, 0x32, 0x32, 0x4F, 0x57 } -}; - -static const unsigned char cs35l41_bst_k2_table[4][5] = { - { 0x24, 0x49, 0x66, 0xA3, 0xEA }, - { 0x24, 0x49, 0x66, 0xA3, 0xEA }, - { 0x48, 0x49, 0x66, 0xA3, 0xEA }, - { 0x48, 0x49, 0x66, 0xA3, 0xEA } -}; - -static const unsigned char cs35l41_bst_slope_table[4] = { - 0x75, 0x6B, 0x3B, 0x28 -}; - static int cs35l41_get_fs_mon_config_index(int freq) { int i; @@ -197,6 +180,75 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, CS35L41_AMP_DIG_VOL_CTRL, 0, cs35l41_pcm_sftramp_text); +static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (cs35l41->dsp.cs_dsp.booted) + return 0; + + return wm_adsp_early_event(w, kcontrol, event); + case SND_SOC_DAPM_PRE_PMD: + if (cs35l41->dsp.preloaded) + return 0; + + if (cs35l41->dsp.cs_dsp.running) { + ret = wm_adsp_event(w, kcontrol, event); + if (ret) + return ret; + } + + return wm_adsp_early_event(w, kcontrol, event); + default: + return 0; + } +} + +static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + unsigned int fw_status; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!cs35l41->dsp.cs_dsp.running) + return wm_adsp_event(w, kcontrol, event); + + ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to read firmware status: %d\n", ret); + return ret; + } + + switch (fw_status) { + case CSPL_MBOX_STS_RUNNING: + case CSPL_MBOX_STS_PAUSED: + break; + default: + dev_err(cs35l41->dev, "Firmware status is invalid: %u\n", + fw_status); + return -EINVAL; + } + + return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_RESUME); + case SND_SOC_DAPM_PRE_PMD: + return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, + CSPL_MBOX_CMD_PAUSE); + default: + return 0; + } +} + static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"}; static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32}; static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum, @@ -255,6 +307,24 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum, static const struct snd_kcontrol_new asp_tx4_mux = SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum); +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx1_enum, + CS35L41_DSP1_RX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx1_mux = + SOC_DAPM_ENUM("DSPRX1 SRC", cs35l41_dsprx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx2_enum, + CS35L41_DSP1_RX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx2_mux = + SOC_DAPM_ENUM("DSPRX2 SRC", cs35l41_dsprx2_enum); + static const struct snd_kcontrol_new cs35l41_aud_controls[] = { SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL, 3, 0x4CF, 0x391, dig_vol_tlv), @@ -264,7 +334,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0), SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0), SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0), - SOC_SINGLE("Aux Noise Gate CH1 Enable", + SOC_SINGLE("Aux Noise Gate CH1 Switch", CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0), SOC_SINGLE("Aux Noise Gate CH1 Entry Delay", CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0), @@ -272,140 +342,20 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0), SOC_SINGLE("Aux Noise Gate CH2 Entry Delay", CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0), - SOC_SINGLE("Aux Noise Gate CH2 Enable", + SOC_SINGLE("Aux Noise Gate CH2 Switch", CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0), SOC_SINGLE("Aux Noise Gate CH2 Threshold", CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0), - SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), - SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), - SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL, + SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL, CS35L41_AMP_INV_PCM_SHIFT, 1, 0), - SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL, + SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL, CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0), + WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + WM_ADSP_FW_CONTROL("DSP1", 0), }; -static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { - if (cs35l41_otp_map_map[i].id == otp_id) - return &cs35l41_otp_map_map[i]; - } - - return NULL; -} - -static int cs35l41_otp_unpack(void *data) -{ - const struct cs35l41_otp_map_element_t *otp_map_match; - const struct cs35l41_otp_packed_element_t *otp_map; - struct cs35l41_private *cs35l41 = data; - int bit_offset, word_offset, ret, i; - unsigned int bit_sum = 8; - u32 otp_val, otp_id_reg; - u32 *otp_mem; - - otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL); - if (!otp_mem) - return -ENOMEM; - - ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); - if (ret < 0) { - dev_err(cs35l41->dev, "Read OTP ID failed: %d\n", ret); - goto err_otp_unpack; - } - - otp_map_match = cs35l41_find_otp_map(otp_id_reg); - - if (!otp_map_match) { - dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", - otp_id_reg); - ret = -EINVAL; - goto err_otp_unpack; - } - - ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem, - CS35L41_OTP_SIZE_WORDS); - if (ret < 0) { - dev_err(cs35l41->dev, "Read OTP Mem failed: %d\n", ret); - goto err_otp_unpack; - } - - otp_map = otp_map_match->map; - - bit_offset = otp_map_match->bit_offset; - word_offset = otp_map_match->word_offset; - - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Unlock key failed 1/2: %d\n", ret); - goto err_otp_unpack; - } - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Unlock key failed 2/2: %d\n", ret); - goto err_otp_unpack; - } - - for (i = 0; i < otp_map_match->num_elements; i++) { - dev_dbg(cs35l41->dev, - "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", - bit_offset, word_offset, bit_sum % 32); - if (bit_offset + otp_map[i].size - 1 >= 32) { - otp_val = (otp_mem[word_offset] & - GENMASK(31, bit_offset)) >> - bit_offset; - otp_val |= (otp_mem[++word_offset] & - GENMASK(bit_offset + - otp_map[i].size - 33, 0)) << - (32 - bit_offset); - bit_offset += otp_map[i].size - 32; - } else { - otp_val = (otp_mem[word_offset] & - GENMASK(bit_offset + otp_map[i].size - 1, - bit_offset)) >> bit_offset; - bit_offset += otp_map[i].size; - } - bit_sum += otp_map[i].size; - - if (bit_offset == 32) { - bit_offset = 0; - word_offset++; - } - - if (otp_map[i].reg != 0) { - ret = regmap_update_bits(cs35l41->regmap, - otp_map[i].reg, - GENMASK(otp_map[i].shift + - otp_map[i].size - 1, - otp_map[i].shift), - otp_val << otp_map[i].shift); - if (ret < 0) { - dev_err(cs35l41->dev, "Write OTP val failed: %d\n", - ret); - goto err_otp_unpack; - } - } - } - - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Lock key failed 1/2: %d\n", ret); - goto err_otp_unpack; - } - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Lock key failed 2/2: %d\n", ret); - goto err_otp_unpack; - } - ret = 0; - -err_otp_unpack: - kfree(otp_mem); - return ret; -} - static irqreturn_t cs35l41_irq(int irq, void *data) { struct cs35l41_private *cs35l41 = data; @@ -414,6 +364,8 @@ static irqreturn_t cs35l41_irq(int irq, void *data) int ret = IRQ_NONE; unsigned int i; + pm_runtime_get_sync(cs35l41->dev); + for (i = 0; i < ARRAY_SIZE(status); i++) { regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE), @@ -426,7 +378,7 @@ static irqreturn_t cs35l41_irq(int irq, void *data) /* Check to see if unmasked bits are active */ if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) && !(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) - return IRQ_NONE; + goto done; if (status[3] & CS35L41_OTP_BOOT_DONE) { regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK4, @@ -531,23 +483,27 @@ static irqreturn_t cs35l41_irq(int irq, void *data) ret = IRQ_HANDLED; } +done: + pm_runtime_mark_last_busy(cs35l41->dev); + pm_runtime_put_autosuspend(cs35l41->dev); + return ret; } static const struct reg_sequence cs35l41_pup_patch[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, + { CS35L41_TEST_KEY_CTL, 0x00000055 }, + { CS35L41_TEST_KEY_CTL, 0x000000AA }, { 0x00002084, 0x002F1AA0 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, + { CS35L41_TEST_KEY_CTL, 0x000000CC }, + { CS35L41_TEST_KEY_CTL, 0x00000033 }, }; static const struct reg_sequence cs35l41_pdn_patch[] = { - { 0x00000040, 0x00000055 }, - { 0x00000040, 0x000000AA }, + { CS35L41_TEST_KEY_CTL, 0x00000055 }, + { CS35L41_TEST_KEY_CTL, 0x000000AA }, { 0x00002084, 0x002F1AA3 }, - { 0x00000040, 0x000000CC }, - { 0x00000040, 0x00000033 }, + { CS35L41_TEST_KEY_CTL, 0x000000CC }, + { CS35L41_TEST_KEY_CTL, 0x00000033 }, }; static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, @@ -559,20 +515,15 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, int ret = 0; switch (event) { - case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMU: regmap_multi_reg_write_bypassed(cs35l41->regmap, cs35l41_pup_patch, ARRAY_SIZE(cs35l41_pup_patch)); - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, - CS35L41_GLOBAL_EN_MASK, - 1 << CS35L41_GLOBAL_EN_SHIFT); - - usleep_range(1000, 1100); + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1); break; case SND_SOC_DAPM_POST_PMD: - regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, - CS35L41_GLOBAL_EN_MASK, 0); + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0); ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, val, val & CS35L41_PDN_DONE_MASK, @@ -596,6 +547,14 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + SND_SOC_DAPM_SPK("DSP1 Preload", NULL), + SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0, + cs35l41_dsp_preload_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, + cs35l41_dsp_audio_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("SPK"), SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0), @@ -611,48 +570,73 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { SND_SOC_DAPM_SIGGEN("VBST"), SND_SOC_DAPM_SIGGEN("TEMP"), - SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0), - SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0), - SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0), - SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0), - SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0), + SND_SOC_DAPM_SUPPLY("VMON", CS35L41_PWR_CTRL2, 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("IMON", CS35L41_PWR_CTRL2, 13, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VPMON", CS35L41_PWR_CTRL2, 8, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VBSTMON", CS35L41_PWR_CTRL2, 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TEMPMON", CS35L41_PWR_CTRL2, 10, 0, NULL, 0), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0), SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0, cs35l41_main_amp_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MUX("ASP TX1 Source", SND_SOC_NOPM, 0, 0, &asp_tx1_mux), SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux), SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux), SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux), + SND_SOC_DAPM_MUX("DSP RX1 Source", SND_SOC_NOPM, 0, 0, &dsp_rx1_mux), + SND_SOC_DAPM_MUX("DSP RX2 Source", SND_SOC_NOPM, 0, 0, &dsp_rx2_mux), SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux), SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl), }; static const struct snd_soc_dapm_route cs35l41_audio_map[] = { + {"DSP RX1 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX1 Source", "ASPRX2", "ASPRX2"}, + {"DSP RX2 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX2 Source", "ASPRX2", "ASPRX2"}, + + {"DSP1", NULL, "DSP RX1 Source"}, + {"DSP1", NULL, "DSP RX2 Source"}, + {"ASP TX1 Source", "VMON", "VMON ADC"}, {"ASP TX1 Source", "IMON", "IMON ADC"}, {"ASP TX1 Source", "VPMON", "VPMON ADC"}, {"ASP TX1 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX1 Source", "DSPTX1", "DSP1"}, + {"ASP TX1 Source", "DSPTX2", "DSP1"}, {"ASP TX1 Source", "ASPRX1", "ASPRX1" }, {"ASP TX1 Source", "ASPRX2", "ASPRX2" }, {"ASP TX2 Source", "VMON", "VMON ADC"}, {"ASP TX2 Source", "IMON", "IMON ADC"}, {"ASP TX2 Source", "VPMON", "VPMON ADC"}, {"ASP TX2 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX2 Source", "DSPTX1", "DSP1"}, + {"ASP TX2 Source", "DSPTX2", "DSP1"}, {"ASP TX2 Source", "ASPRX1", "ASPRX1" }, {"ASP TX2 Source", "ASPRX2", "ASPRX2" }, {"ASP TX3 Source", "VMON", "VMON ADC"}, {"ASP TX3 Source", "IMON", "IMON ADC"}, {"ASP TX3 Source", "VPMON", "VPMON ADC"}, {"ASP TX3 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX3 Source", "DSPTX1", "DSP1"}, + {"ASP TX3 Source", "DSPTX2", "DSP1"}, {"ASP TX3 Source", "ASPRX1", "ASPRX1" }, {"ASP TX3 Source", "ASPRX2", "ASPRX2" }, {"ASP TX4 Source", "VMON", "VMON ADC"}, {"ASP TX4 Source", "IMON", "IMON ADC"}, {"ASP TX4 Source", "VPMON", "VPMON ADC"}, {"ASP TX4 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX4 Source", "DSPTX1", "DSP1"}, + {"ASP TX4 Source", "DSPTX2", "DSP1"}, {"ASP TX4 Source", "ASPRX1", "ASPRX1" }, {"ASP TX4 Source", "ASPRX2", "ASPRX2" }, {"ASPTX1", NULL, "ASP TX1 Source"}, @@ -664,12 +648,27 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { {"AMP Capture", NULL, "ASPTX3"}, {"AMP Capture", NULL, "ASPTX4"}, + {"DSP1", NULL, "VMON"}, + {"DSP1", NULL, "IMON"}, + {"DSP1", NULL, "VPMON"}, + {"DSP1", NULL, "VBSTMON"}, + {"DSP1", NULL, "TEMPMON"}, + + {"VMON ADC", NULL, "VMON"}, + {"IMON ADC", NULL, "IMON"}, + {"VPMON ADC", NULL, "VPMON"}, + {"VBSTMON ADC", NULL, "VBSTMON"}, + {"TEMPMON ADC", NULL, "TEMPMON"}, + {"VMON ADC", NULL, "VSENSE"}, {"IMON ADC", NULL, "ISENSE"}, {"VPMON ADC", NULL, "VP"}, {"VBSTMON ADC", NULL, "VBST"}, {"TEMPMON ADC", NULL, "TEMP"}, + {"DSP1 Preload", NULL, "DSP1 Preloader"}, + {"DSP1", NULL, "DSP1 Preloader"}, + {"ASPRX1", NULL, "AMP Playback"}, {"ASPRX2", NULL, "AMP Playback"}, {"DRE", "Switch", "CLASS H"}, @@ -678,39 +677,16 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { {"SPK", NULL, "Main AMP"}, {"PCM Source", "ASP", "ASPRX1"}, + {"PCM Source", "DSP", "DSP1"}, {"CLASS H", NULL, "PCM Source"}, }; -static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, - unsigned int *tx_slot, unsigned int rx_num, - unsigned int *rx_slot) +static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n, + unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot) { struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); - unsigned int val, mask; - int i; - - if (tx_num > 4 || rx_num > 2) - return -EINVAL; - val = 0; - mask = 0; - for (i = 0; i < rx_num; i++) { - dev_dbg(cs35l41->dev, "rx slot %d position = %d\n", i, rx_slot[i]); - val |= rx_slot[i] << (i * 8); - mask |= 0x3F << (i * 8); - } - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_RX_SLOT, mask, val); - - val = 0; - mask = 0; - for (i = 0; i < tx_num; i++) { - dev_dbg(cs35l41->dev, "tx slot %d position = %d\n", i, tx_slot[i]); - val |= tx_slot[i] << (i * 8); - mask |= 0x3F << (i * 8); - } - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_TX_SLOT, mask, val); - - return 0; + return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_n, tx_slot, rx_n, rx_slot); } static int cs35l41_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -946,149 +922,64 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, return 0; } -static int cs35l41_boost_config(struct cs35l41_private *cs35l41, - int boost_ind, int boost_cap, int boost_ipk) +static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) { - unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; - struct regmap *regmap = cs35l41->regmap; - struct device *dev = cs35l41->dev; + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; int ret; - switch (boost_ind) { - case 1000: /* 1.0 uH */ - bst_lbst_val = 0; - break; - case 1200: /* 1.2 uH */ - bst_lbst_val = 1; - break; - case 1500: /* 1.5 uH */ - bst_lbst_val = 2; - break; - case 2200: /* 2.2 uH */ - bst_lbst_val = 3; - break; - default: - dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind); + if (!hw_cfg->valid) return -EINVAL; - } - switch (boost_cap) { - case 0 ... 19: - bst_cbst_range = 0; - break; - case 20 ... 50: - bst_cbst_range = 1; - break; - case 51 ... 100: - bst_cbst_range = 2; - break; - case 101 ... 200: - bst_cbst_range = 3; - break; - default: /* 201 uF and greater */ - bst_cbst_range = 4; - } - - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, - CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, - cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] - << CS35L41_BST_K1_SHIFT | - cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] - << CS35L41_BST_K2_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost coefficients: %d\n", ret); - return ret; - } - - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, - CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK, - cs35l41_bst_slope_table[bst_lbst_val] - << CS35L41_BST_SLOPE_SHIFT | - bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret); - return ret; - } - - if (boost_ipk < 1600 || boost_ipk > 4500) { - dev_err(dev, "Invalid boost inductor peak current: %d mA\n", - boost_ipk); + if (hw_cfg->bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) return -EINVAL; - } - bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, - CS35L41_BST_IPK_MASK, - bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret); + /* Required */ + ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg); + if (ret) return ret; - } + + /* Optional */ + if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, CS35L41_ASP_DOUT_HIZ_MASK, + hw_cfg->dout_hiz); return 0; } -static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) +static const struct snd_soc_dapm_route cs35l41_ext_bst_routes[] = { + {"Main AMP", NULL, "VSPK"}, +}; + +static const struct snd_soc_dapm_widget cs35l41_ext_bst_widget[] = { + SND_SOC_DAPM_SUPPLY("VSPK", CS35L41_GPIO1_CTRL1, CS35L41_GPIO_LVL_SHIFT, 0, NULL, 0), +}; + +static int cs35l41_component_probe(struct snd_soc_component *component) { + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); int ret; - /* Set Platform Data */ - /* Required */ - if (cs35l41->pdata.bst_ipk && - cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { - ret = cs35l41_boost_config(cs35l41, cs35l41->pdata.bst_ind, - cs35l41->pdata.bst_cap, - cs35l41->pdata.bst_ipk); - if (ret) { - dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret); + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) { + ret = snd_soc_dapm_new_controls(dapm, cs35l41_ext_bst_widget, + ARRAY_SIZE(cs35l41_ext_bst_widget)); + if (ret) return ret; - } - } else { - dev_err(cs35l41->dev, "Incomplete Boost component DT config\n"); - return -EINVAL; - } - /* Optional */ - if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && - cs35l41->pdata.dout_hiz >= 0) - regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, - CS35L41_ASP_DOUT_HIZ_MASK, - cs35l41->pdata.dout_hiz); + ret = snd_soc_dapm_add_routes(dapm, cs35l41_ext_bst_routes, + ARRAY_SIZE(cs35l41_ext_bst_routes)); + if (ret) + return ret; + } - return 0; + return wm_adsp2_component_probe(&cs35l41->dsp, component); } -static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) +static void cs35l41_component_remove(struct snd_soc_component *component) { - struct cs35l41_irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1; - struct cs35l41_irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2; - int irq_pol = IRQF_TRIGGER_NONE; - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO1_CTRL1, - CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, - irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | - !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO2_CTRL1, - CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, - irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | - !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); - - regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, - CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK, - irq_gpio_cfg1->irq_src_sel << CS35L41_GPIO1_CTRL_SHIFT | - irq_gpio_cfg2->irq_src_sel << CS35L41_GPIO2_CTRL_SHIFT); - - if ((irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) || - (irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_OPEN_INT | CS35L41_VALID_PDATA))) - irq_pol = IRQF_TRIGGER_LOW; - else if (irq_gpio_cfg2->irq_src_sel == - (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA)) - irq_pol = IRQF_TRIGGER_HIGH; - - return irq_pol; + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + + wm_adsp2_component_remove(&cs35l41->dsp, component); } static const struct snd_soc_dai_ops cs35l41_ops = { @@ -1113,7 +1004,7 @@ static struct snd_soc_dai_driver cs35l41_dai[] = { .capture = { .stream_name = "AMP Capture", .channels_min = 1, - .channels_max = 8, + .channels_max = 4, .rates = SNDRV_PCM_RATE_KNOT, .formats = CS35L41_TX_FORMATS, }, @@ -1124,6 +1015,8 @@ static struct snd_soc_dai_driver cs35l41_dai[] = { static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { .name = "cs35l41-codec", + .probe = cs35l41_component_probe, + .remove = cs35l41_component_remove, .dapm_widgets = cs35l41_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets), @@ -1133,114 +1026,157 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { .controls = cs35l41_aud_controls, .num_controls = ARRAY_SIZE(cs35l41_aud_controls), .set_sysclk = cs35l41_component_set_sysclk, + + .endianness = 1, }; -static int cs35l41_handle_pdata(struct device *dev, - struct cs35l41_platform_data *pdata, - struct cs35l41_private *cs35l41) +static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cfg) { - struct cs35l41_irq_cfg *irq_gpio1_config = &pdata->irq_config1; - struct cs35l41_irq_cfg *irq_gpio2_config = &pdata->irq_config2; + struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1; + struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2; unsigned int val; int ret; + ret = device_property_read_u32(dev, "cirrus,boost-type", &val); + if (ret >= 0) + hw_cfg->bst_type = val; + ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val); if (ret >= 0) - pdata->bst_ipk = val; + hw_cfg->bst_ipk = val; + else + hw_cfg->bst_ipk = -1; ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val); if (ret >= 0) - pdata->bst_ind = val; + hw_cfg->bst_ind = val; + else + hw_cfg->bst_ind = -1; ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val); if (ret >= 0) - pdata->bst_cap = val; + hw_cfg->bst_cap = val; + else + hw_cfg->bst_cap = -1; ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val); if (ret >= 0) - pdata->dout_hiz = val; + hw_cfg->dout_hiz = val; else - pdata->dout_hiz = -1; + hw_cfg->dout_hiz = -1; /* GPIO1 Pin Config */ - irq_gpio1_config->irq_pol_inv = device_property_read_bool(dev, - "cirrus,gpio1-polarity-invert"); - irq_gpio1_config->irq_out_en = device_property_read_bool(dev, - "cirrus,gpio1-output-enable"); - ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", - &val); - if (ret >= 0) - irq_gpio1_config->irq_src_sel = val | CS35L41_VALID_PDATA; + gpio1->pol_inv = device_property_read_bool(dev, "cirrus,gpio1-polarity-invert"); + gpio1->out_en = device_property_read_bool(dev, "cirrus,gpio1-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", &val); + if (ret >= 0) { + gpio1->func = val; + gpio1->valid = true; + } /* GPIO2 Pin Config */ - irq_gpio2_config->irq_pol_inv = device_property_read_bool(dev, - "cirrus,gpio2-polarity-invert"); - irq_gpio2_config->irq_out_en = device_property_read_bool(dev, - "cirrus,gpio2-output-enable"); - ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", - &val); - if (ret >= 0) - irq_gpio2_config->irq_src_sel = val | CS35L41_VALID_PDATA; + gpio2->pol_inv = device_property_read_bool(dev, "cirrus,gpio2-polarity-invert"); + gpio2->out_en = device_property_read_bool(dev, "cirrus,gpio2-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", &val); + if (ret >= 0) { + gpio2->func = val; + gpio2->valid = true; + } + + hw_cfg->valid = true; return 0; } -static const struct reg_sequence cs35l41_reva0_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { 0x00003854, 0x05180240 }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, - { 0x00003014, 0x0200EE0E }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { 0x00000054, 0x00000004 }, - { CS35L41_IRQ1_DB3, 0x00000000 }, - { CS35L41_IRQ2_DB3, 0x00000000 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, -}; +static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) +{ + struct wm_adsp *dsp; + int ret; -static const struct reg_sequence cs35l41_revb0_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, -}; + dsp = &cs35l41->dsp; + dsp->part = "cs35l41"; + dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */ + dsp->toggle_preload = true; -static const struct reg_sequence cs35l41_revb2_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, -}; + cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, &dsp->cs_dsp); + + ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap); + if (ret < 0) + return ret; -int cs35l41_probe(struct cs35l41_private *cs35l41, - struct cs35l41_platform_data *pdata) + ret = wm_halo_init(dsp); + if (ret) { + dev_err(cs35l41->dev, "wm_halo_init failed: %d\n", ret); + return ret; + } + + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, + CS35L41_INPUT_SRC_VPMON); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, + CS35L41_INPUT_SRC_CLASSH); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC, + CS35L41_INPUT_SRC_TEMPMON); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_TEMPMON failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX8_SRC, + CS35L41_INPUT_SRC_RSVD); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_RSVD failed: %d\n", ret); + goto err_dsp; + } + + return 0; + +err_dsp: + wm_adsp2_remove(dsp); + + return ret; +} + +static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41) +{ + acpi_handle handle = ACPI_HANDLE(cs35l41->dev); + const char *sub; + + /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ + if (!handle) + return 0; + + sub = acpi_get_subsystem_id(handle); + if (IS_ERR(sub)) { + /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ + if (PTR_ERR(sub) == -ENODATA) + return 0; + else + return PTR_ERR(sub); + } + + cs35l41->dsp.system_name = sub; + dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name); + + return 0; +} + +int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg) { u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; int irq_pol = 0; int ret; - if (pdata) { - cs35l41->pdata = *pdata; + if (hw_cfg) { + cs35l41->hw_cfg = *hw_cfg; } else { - ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata, cs35l41); + ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->hw_cfg); if (ret != 0) return ret; } @@ -1325,40 +1261,21 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } - switch (reg_revid) { - case CS35L41_REVID_A0: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_reva0_errata_patch, - ARRAY_SIZE(cs35l41_reva0_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply A0 errata patch: %d\n", ret); - goto err; - } - break; - case CS35L41_REVID_B0: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_revb0_errata_patch, - ARRAY_SIZE(cs35l41_revb0_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply B0 errata patch: %d\n", ret); - goto err; - } - break; - case CS35L41_REVID_B2: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_revb2_errata_patch, - ARRAY_SIZE(cs35l41_revb2_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply B2 errata patch: %d\n", ret); - goto err; - } - break; + cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); + + ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid); + if (ret) + goto err; + + ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap); + if (ret < 0) { + dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); + goto err; } - irq_pol = cs35l41_irq_gpio_config(cs35l41); + cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); + + irq_pol = cs35l41_gpio_config(cs35l41->regmap, &cs35l41->hw_cfg); /* Set interrupt masks for critical errors */ regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, @@ -1367,71 +1284,171 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq, IRQF_ONESHOT | IRQF_SHARED | irq_pol, "cs35l41", cs35l41); - - /* CS35L41 needs INT for PDN_DONE */ if (ret != 0) { dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); goto err; } - ret = cs35l41_otp_unpack(cs35l41); + ret = cs35l41_set_pdata(cs35l41); if (ret < 0) { - dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); + dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); goto err; } - ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_CCM_CORE_CTRL, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CCM_CORE_CTRL failed: %d\n", ret); + ret = cs35l41_acpi_get_name(cs35l41); + if (ret < 0) goto err; - } - ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, - CS35L41_AMP_EN_MASK, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed: %d\n", ret); + ret = cs35l41_dsp_init(cs35l41); + if (ret < 0) goto err; - } - ret = regmap_update_bits(cs35l41->regmap, CS35L41_AMP_GAIN_CTRL, - CS35L41_AMP_GAIN_PCM_MASK, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CS35L41_AMP_GAIN_CTRL failed: %d\n", ret); - goto err; - } - - ret = cs35l41_set_pdata(cs35l41); - if (ret < 0) { - dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); - goto err; - } + pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); + pm_runtime_use_autosuspend(cs35l41->dev); + pm_runtime_mark_last_busy(cs35l41->dev); + pm_runtime_set_active(cs35l41->dev); + pm_runtime_get_noresume(cs35l41->dev); + pm_runtime_enable(cs35l41->dev); ret = devm_snd_soc_register_component(cs35l41->dev, &soc_component_dev_cs35l41, cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); if (ret < 0) { dev_err(cs35l41->dev, "Register codec failed: %d\n", ret); - goto err; + goto err_pm; } + pm_runtime_put_autosuspend(cs35l41->dev); + dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid); return 0; +err_pm: + pm_runtime_disable(cs35l41->dev); + pm_runtime_put_noidle(cs35l41->dev); + + wm_adsp2_remove(&cs35l41->dsp); err: + cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); return ret; } +EXPORT_SYMBOL_GPL(cs35l41_probe); void cs35l41_remove(struct cs35l41_private *cs35l41) { + pm_runtime_get_sync(cs35l41->dev); + pm_runtime_disable(cs35l41->dev); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + kfree(cs35l41->dsp.system_name); + wm_adsp2_remove(&cs35l41->dsp); + cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); + + pm_runtime_put_noidle(cs35l41->dev); + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); } +EXPORT_SYMBOL_GPL(cs35l41_remove); + +static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "Runtime suspend\n"); + + if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running) + return 0; + + cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); + + regcache_cache_only(cs35l41->regmap, true); + regcache_mark_dirty(cs35l41->regmap); + + return 0; +} + +static int __maybe_unused cs35l41_runtime_resume(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + int ret; + + dev_dbg(cs35l41->dev, "Runtime resume\n"); + + if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running) + return 0; + + regcache_cache_only(cs35l41->regmap, false); + + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); + if (ret) + return ret; + + /* Test key needs to be unlocked to allow the OTP settings to re-apply */ + cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); + ret = regcache_sync(cs35l41->regmap); + cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); + if (ret) { + dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); + return ret; + } + cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg); + + return 0; +} + +static int __maybe_unused cs35l41_sys_suspend(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "System suspend, disabling IRQ\n"); + disable_irq(cs35l41->irq); + + return 0; +} + +static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "Late system suspend, reenabling IRQ\n"); + enable_irq(cs35l41->irq); + + return 0; +} + +static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "Early system resume, disabling IRQ\n"); + disable_irq(cs35l41->irq); + + return 0; +} + +static int __maybe_unused cs35l41_sys_resume(struct device *dev) +{ + struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); + + dev_dbg(cs35l41->dev, "System resume, reenabling IRQ\n"); + enable_irq(cs35l41->irq); + + return 0; +} + +const struct dev_pm_ops cs35l41_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL) + + SET_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq) +}; +EXPORT_SYMBOL_GPL(cs35l41_pm_ops); MODULE_DESCRIPTION("ASoC CS35L41 driver"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h index 48485b08a6f1..c85cbc1dd333 100644 --- a/sound/soc/codecs/cs35l41.h +++ b/sound/soc/codecs/cs35l41.h @@ -11,753 +11,22 @@ #define __CS35L41_H__ #include <linux/gpio/consumer.h> -#include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/firmware.h> #include <sound/core.h> #include <sound/cs35l41.h> -#define CS35L41_FIRSTREG 0x00000000 -#define CS35L41_LASTREG 0x03804FE8 -#define CS35L41_DEVID 0x00000000 -#define CS35L41_REVID 0x00000004 -#define CS35L41_FABID 0x00000008 -#define CS35L41_RELID 0x0000000C -#define CS35L41_OTPID 0x00000010 -#define CS35L41_SFT_RESET 0x00000020 -#define CS35L41_TEST_KEY_CTL 0x00000040 -#define CS35L41_USER_KEY_CTL 0x00000044 -#define CS35L41_OTP_MEM0 0x00000400 -#define CS35L41_OTP_MEM31 0x0000047C -#define CS35L41_OTP_CTRL0 0x00000500 -#define CS35L41_OTP_CTRL1 0x00000504 -#define CS35L41_OTP_CTRL3 0x00000508 -#define CS35L41_OTP_CTRL4 0x0000050C -#define CS35L41_OTP_CTRL5 0x00000510 -#define CS35L41_OTP_CTRL6 0x00000514 -#define CS35L41_OTP_CTRL7 0x00000518 -#define CS35L41_OTP_CTRL8 0x0000051C -#define CS35L41_PWR_CTRL1 0x00002014 -#define CS35L41_PWR_CTRL2 0x00002018 -#define CS35L41_PWR_CTRL3 0x0000201C -#define CS35L41_CTRL_OVRRIDE 0x00002020 -#define CS35L41_AMP_OUT_MUTE 0x00002024 -#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 -#define CS35L41_GPIO_PAD_CONTROL 0x0000242C -#define CS35L41_JTAG_CONTROL 0x00002438 -#define CS35L41_PLL_CLK_CTRL 0x00002C04 -#define CS35L41_DSP_CLK_CTRL 0x00002C08 -#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C -#define CS35L41_DATA_FS_SEL 0x00002C10 -#define CS35L41_TST_FS_MON0 0x00002D10 -#define CS35L41_MDSYNC_EN 0x00003400 -#define CS35L41_MDSYNC_TX_ID 0x00003408 -#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C -#define CS35L41_MDSYNC_DATA_TX 0x00003410 -#define CS35L41_MDSYNC_TX_STATUS 0x00003414 -#define CS35L41_MDSYNC_DATA_RX 0x0000341C -#define CS35L41_MDSYNC_RX_STATUS 0x00003420 -#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 -#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 -#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C -#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C -#define CS35L41_BSTCVRT_VCTRL1 0x00003800 -#define CS35L41_BSTCVRT_VCTRL2 0x00003804 -#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 -#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C -#define CS35L41_BSTCVRT_COEFF 0x00003810 -#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 -#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 -#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C -#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 -#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 -#define CS35L41_VI_VOL_POL 0x00004000 -#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 -#define CS35L41_DTEMP_WARN_THLD 0x00004220 -#define CS35L41_DTEMP_CFG 0x00004224 -#define CS35L41_DTEMP_EN 0x00004308 -#define CS35L41_VPVBST_FS_SEL 0x00004400 -#define CS35L41_SP_ENABLES 0x00004800 -#define CS35L41_SP_RATE_CTRL 0x00004804 -#define CS35L41_SP_FORMAT 0x00004808 -#define CS35L41_SP_HIZ_CTRL 0x0000480C -#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 -#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 -#define CS35L41_SP_TX_WL 0x00004830 -#define CS35L41_SP_RX_WL 0x00004840 -#define CS35L41_ASP_CONTROL4 0x00004854 -#define CS35L41_DAC_PCM1_SRC 0x00004C00 -#define CS35L41_ASP_TX1_SRC 0x00004C20 -#define CS35L41_ASP_TX2_SRC 0x00004C24 -#define CS35L41_ASP_TX3_SRC 0x00004C28 -#define CS35L41_ASP_TX4_SRC 0x00004C2C -#define CS35L41_DSP1_RX1_SRC 0x00004C40 -#define CS35L41_DSP1_RX2_SRC 0x00004C44 -#define CS35L41_DSP1_RX3_SRC 0x00004C48 -#define CS35L41_DSP1_RX4_SRC 0x00004C4C -#define CS35L41_DSP1_RX5_SRC 0x00004C50 -#define CS35L41_DSP1_RX6_SRC 0x00004C54 -#define CS35L41_DSP1_RX7_SRC 0x00004C58 -#define CS35L41_DSP1_RX8_SRC 0x00004C5C -#define CS35L41_NGATE1_SRC 0x00004C60 -#define CS35L41_NGATE2_SRC 0x00004C64 -#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 -#define CS35L41_VPBR_CFG 0x00006404 -#define CS35L41_VBBR_CFG 0x00006408 -#define CS35L41_VPBR_STATUS 0x0000640C -#define CS35L41_VBBR_STATUS 0x00006410 -#define CS35L41_OVERTEMP_CFG 0x00006414 -#define CS35L41_AMP_ERR_VOL 0x00006418 -#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 -#define CS35L41_CLASSH_CFG 0x00006800 -#define CS35L41_WKFET_CFG 0x00006804 -#define CS35L41_NG_CFG 0x00006808 -#define CS35L41_AMP_GAIN_CTRL 0x00006C04 -#define CS35L41_DAC_MSM_CFG 0x00007400 -#define CS35L41_IRQ1_CFG 0x00010000 -#define CS35L41_IRQ1_STATUS 0x00010004 -#define CS35L41_IRQ1_STATUS1 0x00010010 -#define CS35L41_IRQ1_STATUS2 0x00010014 -#define CS35L41_IRQ1_STATUS3 0x00010018 -#define CS35L41_IRQ1_STATUS4 0x0001001C -#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 -#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 -#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 -#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C -#define CS35L41_IRQ1_MASK1 0x00010110 -#define CS35L41_IRQ1_MASK2 0x00010114 -#define CS35L41_IRQ1_MASK3 0x00010118 -#define CS35L41_IRQ1_MASK4 0x0001011C -#define CS35L41_IRQ1_FRC1 0x00010190 -#define CS35L41_IRQ1_FRC2 0x00010194 -#define CS35L41_IRQ1_FRC3 0x00010198 -#define CS35L41_IRQ1_FRC4 0x0001019C -#define CS35L41_IRQ1_EDGE1 0x00010210 -#define CS35L41_IRQ1_EDGE4 0x0001021C -#define CS35L41_IRQ1_POL1 0x00010290 -#define CS35L41_IRQ1_POL2 0x00010294 -#define CS35L41_IRQ1_POL3 0x00010298 -#define CS35L41_IRQ1_POL4 0x0001029C -#define CS35L41_IRQ1_DB3 0x00010318 -#define CS35L41_IRQ2_CFG 0x00010800 -#define CS35L41_IRQ2_STATUS 0x00010804 -#define CS35L41_IRQ2_STATUS1 0x00010810 -#define CS35L41_IRQ2_STATUS2 0x00010814 -#define CS35L41_IRQ2_STATUS3 0x00010818 -#define CS35L41_IRQ2_STATUS4 0x0001081C -#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 -#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 -#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 -#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C -#define CS35L41_IRQ2_MASK1 0x00010910 -#define CS35L41_IRQ2_MASK2 0x00010914 -#define CS35L41_IRQ2_MASK3 0x00010918 -#define CS35L41_IRQ2_MASK4 0x0001091C -#define CS35L41_IRQ2_FRC1 0x00010990 -#define CS35L41_IRQ2_FRC2 0x00010994 -#define CS35L41_IRQ2_FRC3 0x00010998 -#define CS35L41_IRQ2_FRC4 0x0001099C -#define CS35L41_IRQ2_EDGE1 0x00010A10 -#define CS35L41_IRQ2_EDGE4 0x00010A1C -#define CS35L41_IRQ2_POL1 0x00010A90 -#define CS35L41_IRQ2_POL2 0x00010A94 -#define CS35L41_IRQ2_POL3 0x00010A98 -#define CS35L41_IRQ2_POL4 0x00010A9C -#define CS35L41_IRQ2_DB3 0x00010B18 -#define CS35L41_GPIO_STATUS1 0x00011000 -#define CS35L41_GPIO1_CTRL1 0x00011008 -#define CS35L41_GPIO2_CTRL1 0x0001100C -#define CS35L41_MIXER_NGATE_CFG 0x00012000 -#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 -#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 -#define CS35L41_DSP_MBOX_1 0x00013000 -#define CS35L41_DSP_MBOX_2 0x00013004 -#define CS35L41_DSP_MBOX_3 0x00013008 -#define CS35L41_DSP_MBOX_4 0x0001300C -#define CS35L41_DSP_MBOX_5 0x00013010 -#define CS35L41_DSP_MBOX_6 0x00013014 -#define CS35L41_DSP_MBOX_7 0x00013018 -#define CS35L41_DSP_MBOX_8 0x0001301C -#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 -#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 -#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 -#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C -#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 -#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 -#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 -#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C -#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 -#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 -#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 -#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C -#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 -#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 -#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 -#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C -#define CS35L41_CLOCK_DETECT_1 0x00014000 -#define CS35L41_TIMER1_CONTROL 0x00015000 -#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 -#define CS35L41_TIMER1_START_STOP 0x0001500C -#define CS35L41_TIMER1_STATUS 0x00015010 -#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 -#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 -#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C -#define CS35L41_TIMER2_CONTROL 0x00015100 -#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 -#define CS35L41_TIMER2_START_STOP 0x0001510C -#define CS35L41_TIMER2_STATUS 0x00015110 -#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 -#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 -#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C -#define CS35L41_DFT_JTAG_CONTROL 0x00016000 -#define CS35L41_DIE_STS1 0x00017040 -#define CS35L41_DIE_STS2 0x00017044 -#define CS35L41_TEMP_CAL1 0x00017048 -#define CS35L41_TEMP_CAL2 0x0001704C -#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 -#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 -#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 -#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 -#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 -#define CS35L41_DSP1_SYS_ID 0x025E0000 -#define CS35L41_DSP1_SYS_VERSION 0x025E0004 -#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 -#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C -#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 -#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 -#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 -#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 -#define CS35L41_DSP1_SYS_FEATURES 0x025E002C -#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 -#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 -#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 -#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C -#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 -#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 -#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 -#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 -#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C -#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 -#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 -#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 -#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C -#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 -#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 -#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 -#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C -#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 -#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 -#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 -#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C -#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 -#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 -#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 -#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 -#define CS35L41_DSP1_CTRL_BASE 0x02B80000 -#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 -#define CS35L41_DSP1_DEBUG 0x02B80040 -#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 -#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 -#define CS35L41_DSP1_RX1_RATE 0x02B80080 -#define CS35L41_DSP1_RX2_RATE 0x02B80088 -#define CS35L41_DSP1_RX3_RATE 0x02B80090 -#define CS35L41_DSP1_RX4_RATE 0x02B80098 -#define CS35L41_DSP1_RX5_RATE 0x02B800A0 -#define CS35L41_DSP1_RX6_RATE 0x02B800A8 -#define CS35L41_DSP1_RX7_RATE 0x02B800B0 -#define CS35L41_DSP1_RX8_RATE 0x02B800B8 -#define CS35L41_DSP1_TX1_RATE 0x02B80280 -#define CS35L41_DSP1_TX2_RATE 0x02B80288 -#define CS35L41_DSP1_TX3_RATE 0x02B80290 -#define CS35L41_DSP1_TX4_RATE 0x02B80298 -#define CS35L41_DSP1_TX5_RATE 0x02B802A0 -#define CS35L41_DSP1_TX6_RATE 0x02B802A8 -#define CS35L41_DSP1_TX7_RATE 0x02B802B0 -#define CS35L41_DSP1_TX8_RATE 0x02B802B8 -#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 -#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 -#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 -#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 -#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 -#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 -#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 -#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 -#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 -#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 -#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 -#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 -#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 -#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 -#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 -#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 -#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 -#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 -#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 -#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 -#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 -#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 -#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 -#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 -#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 -#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 -#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 -#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 -#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 -#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 -#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 -#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 -#define CS35L41_DSP1_SCRATCH1 0x02B805C0 -#define CS35L41_DSP1_SCRATCH2 0x02B805C8 -#define CS35L41_DSP1_SCRATCH3 0x02B805D0 -#define CS35L41_DSP1_SCRATCH4 0x02B805D8 -#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 -#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 -#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 -#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 -#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 -#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 -#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 -#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 -#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 -#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 -#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 -#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 -#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 -#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 -#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 -#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 -#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C -#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 -#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 -#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 -#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C -#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 -#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 -#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 -#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC -#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 -#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 -#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 -#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC -#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 -#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 -#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 -#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC -#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 -#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 -#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 -#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC -#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 -#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 -#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 -#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC -#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 -#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 -#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 -#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC -#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 -#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 -#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 -#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 -#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 -#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C -#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 -#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 -#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C -#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 -#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 -#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C -#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 -#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 -#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 -#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C -#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 -#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 -#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C -#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 -#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 -#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C -#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 -#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 -#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 -#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C -#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 -#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 -#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 -#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 -#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 -#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 -#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 -#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C -#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 -#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 -#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 -#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C -#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 -#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 -#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 -#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C -#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 -#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 -#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 -#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C -#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 -#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 -#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 -#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C -#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 -#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 -#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 -#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C -#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 -#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 -#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 -#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C -#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 -#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 -#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 -#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C -#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 -#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 -#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 -#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 -#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 -#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 -#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 -#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 -#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 -#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 -#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 -#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C -#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 -#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 -#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 -#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C -#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 -#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 -#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 -#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 -#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 -#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 -#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 -#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 -#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 -#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 -#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 -#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 -#define CS35L41_DSP1_PMEM_0 0x03800000 -#define CS35L41_DSP1_PMEM_5114 0x03804FE8 - -/*test regs for emulation bringup*/ -#define CS35L41_PLL_OVR 0x00003018 -#define CS35L41_BST_TEST_DUTY 0x00003900 -#define CS35L41_DIGPWM_IOCTRL 0x0000706C - -/*registers populated by OTP*/ -#define CS35L41_OTP_TRIM_1 0x0000208c -#define CS35L41_OTP_TRIM_2 0x00002090 -#define CS35L41_OTP_TRIM_3 0x00003010 -#define CS35L41_OTP_TRIM_4 0x0000300C -#define CS35L41_OTP_TRIM_5 0x0000394C -#define CS35L41_OTP_TRIM_6 0x00003950 -#define CS35L41_OTP_TRIM_7 0x00003954 -#define CS35L41_OTP_TRIM_8 0x00003958 -#define CS35L41_OTP_TRIM_9 0x0000395C -#define CS35L41_OTP_TRIM_10 0x0000416C -#define CS35L41_OTP_TRIM_11 0x00004160 -#define CS35L41_OTP_TRIM_12 0x00004170 -#define CS35L41_OTP_TRIM_13 0x00004360 -#define CS35L41_OTP_TRIM_14 0x00004448 -#define CS35L41_OTP_TRIM_15 0x0000444C -#define CS35L41_OTP_TRIM_16 0x00006E30 -#define CS35L41_OTP_TRIM_17 0x00006E34 -#define CS35L41_OTP_TRIM_18 0x00006E38 -#define CS35L41_OTP_TRIM_19 0x00006E3C -#define CS35L41_OTP_TRIM_20 0x00006E40 -#define CS35L41_OTP_TRIM_21 0x00006E44 -#define CS35L41_OTP_TRIM_22 0x00006E48 -#define CS35L41_OTP_TRIM_23 0x00006E4C -#define CS35L41_OTP_TRIM_24 0x00006E50 -#define CS35L41_OTP_TRIM_25 0x00006E54 -#define CS35L41_OTP_TRIM_26 0x00006E58 -#define CS35L41_OTP_TRIM_27 0x00006E5C -#define CS35L41_OTP_TRIM_28 0x00006E60 -#define CS35L41_OTP_TRIM_29 0x00006E64 -#define CS35L41_OTP_TRIM_30 0x00007418 -#define CS35L41_OTP_TRIM_31 0x0000741C -#define CS35L41_OTP_TRIM_32 0x00007434 -#define CS35L41_OTP_TRIM_33 0x00007068 -#define CS35L41_OTP_TRIM_34 0x0000410C -#define CS35L41_OTP_TRIM_35 0x0000400C -#define CS35L41_OTP_TRIM_36 0x00002030 - -#define CS35L41_MAX_CACHE_REG 36 -#define CS35L41_OTP_SIZE_WORDS 32 -#define CS35L41_NUM_OTP_ELEM 100 -#define CS35L41_NUM_OTP_MAPS 5 - -#define CS35L41_VALID_PDATA 0x80000000 -#define CS35L41_NUM_SUPPLIES 2 - -#define CS35L41_SCLK_MSTR_MASK 0x10 -#define CS35L41_SCLK_MSTR_SHIFT 4 -#define CS35L41_LRCLK_MSTR_MASK 0x01 -#define CS35L41_LRCLK_MSTR_SHIFT 0 -#define CS35L41_SCLK_INV_MASK 0x40 -#define CS35L41_SCLK_INV_SHIFT 6 -#define CS35L41_LRCLK_INV_MASK 0x04 -#define CS35L41_LRCLK_INV_SHIFT 2 -#define CS35L41_SCLK_FRC_MASK 0x20 -#define CS35L41_SCLK_FRC_SHIFT 5 -#define CS35L41_LRCLK_FRC_MASK 0x02 -#define CS35L41_LRCLK_FRC_SHIFT 1 - -#define CS35L41_AMP_GAIN_PCM_MASK 0x3E0 -#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 -#define CS35L41_AMP_GAIN_ZC_SHIFT 10 - -#define CS35L41_BST_CTL_MASK 0xFF -#define CS35L41_BST_CTL_SEL_MASK 0x03 -#define CS35L41_BST_CTL_SEL_REG 0x00 -#define CS35L41_BST_CTL_SEL_CLASSH 0x01 -#define CS35L41_BST_IPK_MASK 0x7F -#define CS35L41_BST_IPK_SHIFT 0 -#define CS35L41_BST_LIM_MASK 0x4 -#define CS35L41_BST_LIM_SHIFT 2 -#define CS35L41_BST_K1_MASK 0x000000FF -#define CS35L41_BST_K1_SHIFT 0 -#define CS35L41_BST_K2_MASK 0x0000FF00 -#define CS35L41_BST_K2_SHIFT 8 -#define CS35L41_BST_SLOPE_MASK 0x0000FF00 -#define CS35L41_BST_SLOPE_SHIFT 8 -#define CS35L41_BST_LBST_VAL_MASK 0x00000003 -#define CS35L41_BST_LBST_VAL_SHIFT 0 - -#define CS35L41_TEMP_THLD_MASK 0x03 -#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF -#define CS35L41_PDM_MODE_MASK 0x01 -#define CS35L41_PDM_MODE_SHIFT 0 - -#define CS35L41_CH_MEM_DEPTH_MASK 0x07 -#define CS35L41_CH_MEM_DEPTH_SHIFT 0 -#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 -#define CS35L41_CH_HDRM_CTL_SHIFT 16 -#define CS35L41_CH_REL_RATE_MASK 0xFF00 -#define CS35L41_CH_REL_RATE_SHIFT 8 -#define CS35L41_CH_WKFET_DLY_MASK 0x001C -#define CS35L41_CH_WKFET_DLY_SHIFT 2 -#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 -#define CS35L41_CH_WKFET_THLD_SHIFT 8 - -#define CS35L41_HW_NG_SEL_MASK 0x3F00 -#define CS35L41_HW_NG_SEL_SHIFT 8 -#define CS35L41_HW_NG_DLY_MASK 0x0070 -#define CS35L41_HW_NG_DLY_SHIFT 4 -#define CS35L41_HW_NG_THLD_MASK 0x0007 -#define CS35L41_HW_NG_THLD_SHIFT 0 - -#define CS35L41_DSP_NG_ENABLE_MASK 0x00010000 -#define CS35L41_DSP_NG_ENABLE_SHIFT 16 -#define CS35L41_DSP_NG_THLD_MASK 0x7 -#define CS35L41_DSP_NG_THLD_SHIFT 0 -#define CS35L41_DSP_NG_DELAY_MASK 0x0F00 -#define CS35L41_DSP_NG_DELAY_SHIFT 8 - -#define CS35L41_ASP_FMT_MASK 0x0700 -#define CS35L41_ASP_FMT_SHIFT 8 -#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 -#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 -#define CS35L41_ASP_WIDTH_16 0x10 -#define CS35L41_ASP_WIDTH_24 0x18 -#define CS35L41_ASP_WIDTH_32 0x20 -#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 -#define CS35L41_ASP_WIDTH_TX_SHIFT 16 -#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 -#define CS35L41_ASP_WIDTH_RX_SHIFT 24 -#define CS35L41_ASP_RX1_SLOT_MASK 0x3F -#define CS35L41_ASP_RX1_SLOT_SHIFT 0 -#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 -#define CS35L41_ASP_RX2_SLOT_SHIFT 8 -#define CS35L41_ASP_RX_WL_MASK 0x3F -#define CS35L41_ASP_TX_WL_MASK 0x3F -#define CS35L41_ASP_RX_WL_SHIFT 0 -#define CS35L41_ASP_TX_WL_SHIFT 0 -#define CS35L41_ASP_SOURCE_MASK 0x7F - -#define CS35L41_INPUT_SRC_ASPRX1 0x08 -#define CS35L41_INPUT_SRC_ASPRX2 0x09 -#define CS35L41_INPUT_SRC_VMON 0x18 -#define CS35L41_INPUT_SRC_IMON 0x19 -#define CS35L41_INPUT_SRC_CLASSH 0x21 -#define CS35L41_INPUT_SRC_VPMON 0x28 -#define CS35L41_INPUT_SRC_VBSTMON 0x29 -#define CS35L41_INPUT_SRC_TEMPMON 0x3A -#define CS35L41_INPUT_SRC_RSVD 0x3B -#define CS35L41_INPUT_DSP_TX1 0x32 -#define CS35L41_INPUT_DSP_TX2 0x33 - -#define CS35L41_PLL_CLK_SEL_MASK 0x07 -#define CS35L41_PLL_CLK_SEL_SHIFT 0 -#define CS35L41_PLL_CLK_EN_MASK 0x10 -#define CS35L41_PLL_CLK_EN_SHIFT 4 -#define CS35L41_PLL_OPENLOOP_MASK 0x0800 -#define CS35L41_PLL_OPENLOOP_SHIFT 11 -#define CS35L41_PLLSRC_SCLK 0 -#define CS35L41_PLLSRC_LRCLK 1 -#define CS35L41_PLLSRC_SELF 3 -#define CS35L41_PLLSRC_PDMCLK 4 -#define CS35L41_PLLSRC_MCLK 5 -#define CS35L41_PLLSRC_SWIRE 7 -#define CS35L41_REFCLK_FREQ_MASK 0x7E0 -#define CS35L41_REFCLK_FREQ_SHIFT 5 - -#define CS35L41_GLOBAL_FS_MASK 0x1F -#define CS35L41_GLOBAL_FS_SHIFT 0 - -#define CS35L41_GLOBAL_EN_MASK 0x01 -#define CS35L41_GLOBAL_EN_SHIFT 0 -#define CS35L41_BST_EN_MASK 0x0030 -#define CS35L41_BST_EN_SHIFT 4 -#define CS35L41_BST_EN_DEFAULT 0x2 -#define CS35L41_AMP_EN_SHIFT 0 -#define CS35L41_AMP_EN_MASK 1 - -#define CS35L41_PDN_DONE_MASK 0x00800000 -#define CS35L41_PDN_DONE_SHIFT 23 -#define CS35L41_PUP_DONE_MASK 0x01000000 -#define CS35L41_PUP_DONE_SHIFT 24 - -#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F -#define CS35L36_PUP_DONE_IRQ_MASK 0xBF - -#define CS35L41_AMP_SHORT_ERR 0x80000000 -#define CS35L41_BST_SHORT_ERR 0x0100 -#define CS35L41_TEMP_WARN 0x8000 -#define CS35L41_TEMP_ERR 0x00020000 -#define CS35L41_BST_OVP_ERR 0x40 -#define CS35L41_BST_DCM_UVP_ERR 0x80 -#define CS35L41_OTP_BOOT_DONE 0x02 -#define CS35L41_PLL_UNLOCK 0x10 -#define CS35L41_OTP_BOOT_ERR 0x80000000 - -#define CS35L41_AMP_SHORT_ERR_RLS 0x02 -#define CS35L41_BST_SHORT_ERR_RLS 0x04 -#define CS35L41_BST_OVP_ERR_RLS 0x08 -#define CS35L41_BST_UVP_ERR_RLS 0x10 -#define CS35L41_TEMP_WARN_ERR_RLS 0x20 -#define CS35L41_TEMP_ERR_RLS 0x40 - -#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F -#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF -#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF - -#define CS35L41_GPIO_DIR_MASK 0x80000000 -#define CS35L41_GPIO_DIR_SHIFT 31 -#define CS35L41_GPIO1_CTRL_MASK 0x00030000 -#define CS35L41_GPIO1_CTRL_SHIFT 16 -#define CS35L41_GPIO2_CTRL_MASK 0x07000000 -#define CS35L41_GPIO2_CTRL_SHIFT 24 -#define CS35L41_GPIO_CTRL_OPEN_INT 2 -#define CS35L41_GPIO_CTRL_ACTV_LO 4 -#define CS35L41_GPIO_CTRL_ACTV_HI 5 -#define CS35L41_GPIO_POL_MASK 0x1000 -#define CS35L41_GPIO_POL_SHIFT 12 - -#define CS35L41_AMP_INV_PCM_SHIFT 14 -#define CS35L41_AMP_INV_PCM_MASK BIT(CS35L41_AMP_INV_PCM_SHIFT) -#define CS35L41_AMP_PCM_VOL_SHIFT 3 -#define CS35L41_AMP_PCM_VOL_MASK (0x7FF << 3) -#define CS35L41_AMP_PCM_VOL_MUTE 0x4CF - -#define CS35L41_CHIP_ID 0x35a40 -#define CS35L41R_CHIP_ID 0x35b40 -#define CS35L41_MTLREVID_MASK 0x0F -#define CS35L41_REVID_A0 0xA0 -#define CS35L41_REVID_B0 0xB0 -#define CS35L41_REVID_B2 0xB2 - -#define CS35L41_HALO_CORE_RESET 0x00000200 - -#define CS35L41_FS1_WINDOW_MASK 0x000007FF -#define CS35L41_FS2_WINDOW_MASK 0x00FFF800 -#define CS35L41_FS2_WINDOW_SHIFT 12 - -#define CS35L41_SPI_MAX_FREQ 4000000 +#include "wm_adsp.h" #define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) #define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -bool cs35l41_readable_reg(struct device *dev, unsigned int reg); -bool cs35l41_precious_reg(struct device *dev, unsigned int reg); -bool cs35l41_volatile_reg(struct device *dev, unsigned int reg); - -struct cs35l41_otp_packed_element_t { - u32 reg; - u8 shift; - u8 size; -}; - -struct cs35l41_otp_map_element_t { - u32 id; - u32 num_elements; - const struct cs35l41_otp_packed_element_t *map; - u32 bit_offset; - u32 word_offset; -}; - -extern const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG]; -extern const struct cs35l41_otp_map_element_t - cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; - -#define CS35L41_REGSTRIDE 4 +extern const struct dev_pm_ops cs35l41_pm_ops; struct cs35l41_private { + struct wm_adsp dsp; /* needs to be first member */ struct snd_soc_codec *codec; - struct cs35l41_platform_data pdata; + struct cs35l41_hw_cfg hw_cfg; struct device *dev; struct regmap *regmap; struct regulator_bulk_data supplies[CS35L41_NUM_SUPPLIES]; @@ -766,8 +35,7 @@ struct cs35l41_private { struct gpio_desc *reset_gpio; }; -int cs35l41_probe(struct cs35l41_private *cs35l41, - struct cs35l41_platform_data *pdata); +int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg); void cs35l41_remove(struct cs35l41_private *cs35l41); #endif /*__CS35L41_H__*/ diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c new file mode 100644 index 000000000000..39d28641429e --- /dev/null +++ b/sound/soc/codecs/cs35l45-i2c.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// +// cs35l45-i2c.c -- CS35L45 I2C driver +// +// Copyright 2019-2022 Cirrus Logic, Inc. +// +// Author: James Schulman <james.schulman@cirrus.com> + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include "cs35l45.h" + +static int cs35l45_i2c_probe(struct i2c_client *client) +{ + struct cs35l45_private *cs35l45; + struct device *dev = &client->dev; + int ret; + + cs35l45 = devm_kzalloc(dev, sizeof(struct cs35l45_private), GFP_KERNEL); + if (!cs35l45) + return -ENOMEM; + + i2c_set_clientdata(client, cs35l45); + cs35l45->regmap = devm_regmap_init_i2c(client, &cs35l45_i2c_regmap); + if (IS_ERR(cs35l45->regmap)) { + ret = PTR_ERR(cs35l45->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + cs35l45->dev = dev; + + return cs35l45_probe(cs35l45); +} + +static void cs35l45_i2c_remove(struct i2c_client *client) +{ + struct cs35l45_private *cs35l45 = i2c_get_clientdata(client); + + cs35l45_remove(cs35l45); +} + +static const struct of_device_id cs35l45_of_match[] = { + { .compatible = "cirrus,cs35l45" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l45_of_match); + +static const struct i2c_device_id cs35l45_id_i2c[] = { + { "cs35l45", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs35l45_id_i2c); + +static struct i2c_driver cs35l45_i2c_driver = { + .driver = { + .name = "cs35l45", + .of_match_table = cs35l45_of_match, + .pm = &cs35l45_pm_ops, + }, + .id_table = cs35l45_id_i2c, + .probe_new = cs35l45_i2c_probe, + .remove = cs35l45_i2c_remove, +}; +module_i2c_driver(cs35l45_i2c_driver); + +MODULE_DESCRIPTION("I2C CS35L45 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_CS35L45); +MODULE_IMPORT_NS(SND_SOC_CS35L45_TABLES); diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c new file mode 100644 index 000000000000..baaf6e0f4fb9 --- /dev/null +++ b/sound/soc/codecs/cs35l45-spi.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// +// cs35l45-spi.c -- CS35L45 SPI driver +// +// Copyright 2019-2022 Cirrus Logic, Inc. +// +// Author: James Schulman <james.schulman@cirrus.com> + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "cs35l45.h" + +static int cs35l45_spi_probe(struct spi_device *spi) +{ + struct cs35l45_private *cs35l45; + struct device *dev = &spi->dev; + int ret; + + cs35l45 = devm_kzalloc(dev, sizeof(struct cs35l45_private), GFP_KERNEL); + if (cs35l45 == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, cs35l45); + cs35l45->regmap = devm_regmap_init_spi(spi, &cs35l45_spi_regmap); + if (IS_ERR(cs35l45->regmap)) { + ret = PTR_ERR(cs35l45->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + cs35l45->dev = dev; + + return cs35l45_probe(cs35l45); +} + +static void cs35l45_spi_remove(struct spi_device *spi) +{ + struct cs35l45_private *cs35l45 = spi_get_drvdata(spi); + + cs35l45_remove(cs35l45); +} + +static const struct of_device_id cs35l45_of_match[] = { + { .compatible = "cirrus,cs35l45" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l45_of_match); + +static const struct spi_device_id cs35l45_id_spi[] = { + { "cs35l45", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, cs35l45_id_spi); + +static struct spi_driver cs35l45_spi_driver = { + .driver = { + .name = "cs35l45", + .of_match_table = cs35l45_of_match, + .pm = &cs35l45_pm_ops, + }, + .id_table = cs35l45_id_spi, + .probe = cs35l45_spi_probe, + .remove = cs35l45_spi_remove, +}; +module_spi_driver(cs35l45_spi_driver); + +MODULE_DESCRIPTION("SPI CS35L45 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_CS35L45); +MODULE_IMPORT_NS(SND_SOC_CS35L45_TABLES); diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c new file mode 100644 index 000000000000..5a2c2e684ef9 --- /dev/null +++ b/sound/soc/codecs/cs35l45-tables.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// +// cs35l45-tables.c -- CS35L45 ALSA SoC audio driver +// +// Copyright 2019-2022 Cirrus Logic, Inc. +// +// Author: James Schulman <james.schulman@cirrus.com> + +#include <linux/module.h> +#include <linux/regmap.h> + +#include "cs35l45.h" + +static const struct reg_sequence cs35l45_patch[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00000044, 0x00000055 }, + { 0x00000044, 0x000000AA }, + { 0x00006480, 0x0830500A }, + { 0x00007C60, 0x1000850B }, + { CS35L45_BOOST_OV_CFG, 0x007000D0 }, + { CS35L45_LDPM_CONFIG, 0x0001B636 }, + { 0x00002C08, 0x00000009 }, + { 0x00006850, 0x0A30FFC4 }, + { 0x00003820, 0x00040100 }, + { 0x00003824, 0x00000000 }, + { 0x00007CFC, 0x62870004 }, + { 0x00007C60, 0x1001850B }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000000 }, + { CS35L45_BOOST_CCM_CFG, 0xF0000003 }, + { CS35L45_BOOST_DCM_CFG, 0x08710220 }, + { CS35L45_ERROR_RELEASE, 0x00200000 }, +}; + +int cs35l45_apply_patch(struct cs35l45_private *cs35l45) +{ + return regmap_register_patch(cs35l45->regmap, cs35l45_patch, + ARRAY_SIZE(cs35l45_patch)); +} +EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, SND_SOC_CS35L45_TABLES); + +static const struct reg_default cs35l45_defaults[] = { + { CS35L45_BLOCK_ENABLES, 0x00003323 }, + { CS35L45_BLOCK_ENABLES2, 0x00000010 }, + { CS35L45_REFCLK_INPUT, 0x00000510 }, + { CS35L45_GLOBAL_SAMPLE_RATE, 0x00000003 }, + { CS35L45_ASP_ENABLES1, 0x00000000 }, + { CS35L45_ASP_CONTROL1, 0x00000028 }, + { CS35L45_ASP_CONTROL2, 0x18180200 }, + { CS35L45_ASP_CONTROL3, 0x00000002 }, + { CS35L45_ASP_FRAME_CONTROL1, 0x03020100 }, + { CS35L45_ASP_FRAME_CONTROL2, 0x00000004 }, + { CS35L45_ASP_FRAME_CONTROL5, 0x00000100 }, + { CS35L45_ASP_DATA_CONTROL1, 0x00000018 }, + { CS35L45_ASP_DATA_CONTROL5, 0x00000018 }, + { CS35L45_DACPCM1_INPUT, 0x00000008 }, + { CS35L45_ASPTX1_INPUT, 0x00000018 }, + { CS35L45_ASPTX2_INPUT, 0x00000019 }, + { CS35L45_ASPTX3_INPUT, 0x00000020 }, + { CS35L45_ASPTX4_INPUT, 0x00000028 }, + { CS35L45_ASPTX5_INPUT, 0x00000048 }, + { CS35L45_AMP_PCM_CONTROL, 0x00100000 }, +}; + +static bool cs35l45_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L45_DEVID ... CS35L45_OTPID: + case CS35L45_SFT_RESET: + case CS35L45_GLOBAL_ENABLES: + case CS35L45_BLOCK_ENABLES: + case CS35L45_BLOCK_ENABLES2: + case CS35L45_ERROR_RELEASE: + case CS35L45_REFCLK_INPUT: + case CS35L45_GLOBAL_SAMPLE_RATE: + case CS35L45_ASP_ENABLES1: + case CS35L45_ASP_CONTROL1: + case CS35L45_ASP_CONTROL2: + case CS35L45_ASP_CONTROL3: + case CS35L45_ASP_FRAME_CONTROL1: + case CS35L45_ASP_FRAME_CONTROL2: + case CS35L45_ASP_FRAME_CONTROL5: + case CS35L45_ASP_DATA_CONTROL1: + case CS35L45_ASP_DATA_CONTROL5: + case CS35L45_DACPCM1_INPUT: + case CS35L45_ASPTX1_INPUT: + case CS35L45_ASPTX2_INPUT: + case CS35L45_ASPTX3_INPUT: + case CS35L45_ASPTX4_INPUT: + case CS35L45_ASPTX5_INPUT: + case CS35L45_AMP_PCM_CONTROL: + case CS35L45_AMP_PCM_HPF_TST: + case CS35L45_IRQ1_EINT_4: + return true; + default: + return false; + } +} + +static bool cs35l45_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L45_DEVID ... CS35L45_OTPID: + case CS35L45_SFT_RESET: + case CS35L45_GLOBAL_ENABLES: + case CS35L45_ERROR_RELEASE: + case CS35L45_AMP_PCM_HPF_TST: /* not cachable */ + case CS35L45_IRQ1_EINT_4: + return true; + default: + return false; + } +} + +const struct regmap_config cs35l45_i2c_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L45_LASTREG, + .reg_defaults = cs35l45_defaults, + .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), + .volatile_reg = cs35l45_volatile_reg, + .readable_reg = cs35l45_readable_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45_TABLES); + +const struct regmap_config cs35l45_spi_regmap = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = 4, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L45_LASTREG, + .reg_defaults = cs35l45_defaults, + .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), + .volatile_reg = cs35l45_volatile_reg, + .readable_reg = cs35l45_readable_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45_TABLES); + +static const struct { + u8 cfg_id; + u32 freq; +} cs35l45_pll_refclk_freq[] = { + { 0x0C, 128000 }, + { 0x0F, 256000 }, + { 0x11, 384000 }, + { 0x12, 512000 }, + { 0x15, 768000 }, + { 0x17, 1024000 }, + { 0x19, 1411200 }, + { 0x1B, 1536000 }, + { 0x1C, 2116800 }, + { 0x1D, 2048000 }, + { 0x1E, 2304000 }, + { 0x1F, 2822400 }, + { 0x21, 3072000 }, + { 0x23, 4233600 }, + { 0x24, 4096000 }, + { 0x25, 4608000 }, + { 0x26, 5644800 }, + { 0x27, 6000000 }, + { 0x28, 6144000 }, + { 0x29, 6350400 }, + { 0x2A, 6912000 }, + { 0x2D, 7526400 }, + { 0x2E, 8467200 }, + { 0x2F, 8192000 }, + { 0x30, 9216000 }, + { 0x31, 11289600 }, + { 0x33, 12288000 }, + { 0x37, 16934400 }, + { 0x38, 18432000 }, + { 0x39, 22579200 }, + { 0x3B, 24576000 }, +}; + +unsigned int cs35l45_get_clk_freq_id(unsigned int freq) +{ + int i; + + if (freq == 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(cs35l45_pll_refclk_freq); ++i) { + if (cs35l45_pll_refclk_freq[i].freq == freq) + return cs35l45_pll_refclk_freq[i].cfg_id; + } + + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, SND_SOC_CS35L45_TABLES); + +MODULE_DESCRIPTION("ASoC CS35L45 driver tables"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c new file mode 100644 index 000000000000..d15b3b77c7eb --- /dev/null +++ b/sound/soc/codecs/cs35l45.c @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// +// cs35l45.c - CS35L45 ALSA SoC audio driver +// +// Copyright 2019-2022 Cirrus Logic, Inc. +// +// Author: James Schulman <james.schulman@cirrus.com> + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "cs35l45.h" + +static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component); + + dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, + CS35L45_GLOBAL_EN_MASK); + + usleep_range(CS35L45_POST_GLOBAL_EN_US, CS35L45_POST_GLOBAL_EN_US + 100); + break; + case SND_SOC_DAPM_PRE_PMD: + usleep_range(CS35L45_PRE_GLOBAL_DIS_US, CS35L45_PRE_GLOBAL_DIS_US + 100); + + regmap_write(cs35l45->regmap, CS35L45_GLOBAL_ENABLES, 0); + break; + default: + break; + } + + return 0; +} + +static const char * const cs35l45_asp_tx_txt[] = { + "Zero", "ASP_RX1", "ASP_RX2", + "VMON", "IMON", "ERR_VOL", + "VDD_BATTMON", "VDD_BSTMON", + "Interpolator", "IL_TARGET", +}; + +static const unsigned int cs35l45_asp_tx_val[] = { + CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2, + CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL, + CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON, + CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET, +}; + +static const struct soc_enum cs35l45_asp_tx_enums[] = { + SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, + cs35l45_asp_tx_val), + SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, + cs35l45_asp_tx_val), + SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, + cs35l45_asp_tx_val), + SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, + cs35l45_asp_tx_val), + SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt, + cs35l45_asp_tx_val), +}; + +static const char * const cs35l45_dac_txt[] = { + "Zero", "ASP_RX1", "ASP_RX2" +}; + +static const unsigned int cs35l45_dac_val[] = { + CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2 +}; + +static const struct soc_enum cs35l45_dacpcm_enums[] = { + SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK, + ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt, + cs35l45_dac_val), +}; + +static const struct snd_kcontrol_new cs35l45_asp_muxes[] = { + SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]), + SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]), + SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]), + SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]), + SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]), +}; + +static const struct snd_kcontrol_new cs35l45_dac_muxes[] = { + SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]), +}; + +static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0, + cs35l45_global_en_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_SIGGEN("VMON_SRC"), + SND_SOC_DAPM_SIGGEN("IMON_SRC"), + SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"), + SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"), + SND_SOC_DAPM_SIGGEN("ERR_VOL"), + SND_SOC_DAPM_SIGGEN("AMP_INTP"), + SND_SOC_DAPM_SIGGEN("IL_TARGET"), + SND_SOC_DAPM_ADC("VMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0), + SND_SOC_DAPM_ADC("IMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0), + SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, CS35L45_BLOCK_ENABLES, + CS35L45_VDD_BATTMON_EN_SHIFT, 0), + SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, CS35L45_BLOCK_ENABLES, + CS35L45_VDD_BSTMON_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0), + + SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX1_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX2_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL, 2, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX3_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX4_EN_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0), + + SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]), + SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]), + SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]), + SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]), + SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]), + + SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]), + + SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("SPK"), +}; + +#define CS35L45_ASP_MUX_ROUTE(name) \ + { name" Source", "ASP_RX1", "ASP_RX1" }, \ + { name" Source", "ASP_RX2", "ASP_RX2" }, \ + { name" Source", "VMON", "VMON" }, \ + { name" Source", "IMON", "IMON" }, \ + { name" Source", "ERR_VOL", "ERR_VOL" }, \ + { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \ + { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \ + { name" Source", "Interpolator", "AMP_INTP" }, \ + { name" Source", "IL_TARGET", "IL_TARGET" } + +#define CS35L45_DAC_MUX_ROUTE(name) \ + { name" Source", "ASP_RX1", "ASP_RX1" }, \ + { name" Source", "ASP_RX2", "ASP_RX2" } + +static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = { + /* Feedback */ + { "VMON", NULL, "VMON_SRC" }, + { "IMON", NULL, "IMON_SRC" }, + { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" }, + { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" }, + + { "Capture", NULL, "ASP_TX1"}, + { "Capture", NULL, "ASP_TX2"}, + { "Capture", NULL, "ASP_TX3"}, + { "Capture", NULL, "ASP_TX4"}, + { "Capture", NULL, "ASP_TX5"}, + { "ASP_TX1", NULL, "ASP_TX1 Source"}, + { "ASP_TX2", NULL, "ASP_TX2 Source"}, + { "ASP_TX3", NULL, "ASP_TX3 Source"}, + { "ASP_TX4", NULL, "ASP_TX4 Source"}, + { "ASP_TX5", NULL, "ASP_TX5 Source"}, + + { "ASP_TX1", NULL, "ASP_EN" }, + { "ASP_TX2", NULL, "ASP_EN" }, + { "ASP_TX3", NULL, "ASP_EN" }, + { "ASP_TX4", NULL, "ASP_EN" }, + { "ASP_TX1", NULL, "GLOBAL_EN" }, + { "ASP_TX2", NULL, "GLOBAL_EN" }, + { "ASP_TX3", NULL, "GLOBAL_EN" }, + { "ASP_TX4", NULL, "GLOBAL_EN" }, + { "ASP_TX5", NULL, "GLOBAL_EN" }, + + CS35L45_ASP_MUX_ROUTE("ASP_TX1"), + CS35L45_ASP_MUX_ROUTE("ASP_TX2"), + CS35L45_ASP_MUX_ROUTE("ASP_TX3"), + CS35L45_ASP_MUX_ROUTE("ASP_TX4"), + CS35L45_ASP_MUX_ROUTE("ASP_TX5"), + + /* Playback */ + { "ASP_RX1", NULL, "Playback" }, + { "ASP_RX2", NULL, "Playback" }, + { "ASP_RX1", NULL, "ASP_EN" }, + { "ASP_RX2", NULL, "ASP_EN" }, + + { "AMP", NULL, "DACPCM1 Source"}, + { "AMP", NULL, "GLOBAL_EN"}, + + CS35L45_DAC_MUX_ROUTE("DACPCM1"), + + { "SPK", NULL, "AMP"}, +}; + +static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true); + +static const struct snd_kcontrol_new cs35l45_controls[] = { + /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */ + SOC_SINGLE_S_TLV("Digital PCM Volume", + CS35L45_AMP_PCM_CONTROL, + CS35L45_AMP_VOL_PCM_SHIFT + 1, + -409, 48, + (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1, + 0, cs35l45_dig_pcm_vol_tlv), +}; + +static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq) +{ + unsigned int val; + int freq_id; + + freq_id = cs35l45_get_clk_freq_id(freq); + if (freq_id < 0) { + dev_err(cs35l45->dev, "Invalid freq: %u\n", freq); + return -EINVAL; + } + + regmap_read(cs35l45->regmap, CS35L45_REFCLK_INPUT, &val); + val = (val & CS35L45_PLL_REFCLK_FREQ_MASK) >> CS35L45_PLL_REFCLK_FREQ_SHIFT; + if (val == freq_id) + return 0; + + regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); + regmap_update_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, + CS35L45_PLL_REFCLK_FREQ_MASK, + freq_id << CS35L45_PLL_REFCLK_FREQ_SHIFT); + regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); + regmap_clear_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_OPEN_LOOP_MASK); + regmap_set_bits(cs35l45->regmap, CS35L45_REFCLK_INPUT, CS35L45_PLL_REFCLK_EN_MASK); + + return 0; +} + +static int cs35l45_asp_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(codec_dai->component); + unsigned int asp_fmt, fsync_inv, bclk_inv; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + dev_err(cs35l45->dev, "Invalid DAI clocking\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = CS35l45_ASP_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = CS35L45_ASP_FMT_I2S; + break; + default: + dev_err(cs35l45->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + fsync_inv = 1; + bclk_inv = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + fsync_inv = 0; + bclk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + fsync_inv = 1; + bclk_inv = 1; + break; + case SND_SOC_DAIFMT_NB_NF: + fsync_inv = 0; + bclk_inv = 0; + break; + default: + dev_warn(cs35l45->dev, "Invalid DAI clock polarity\n"); + return -EINVAL; + } + + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, + CS35L45_ASP_FMT_MASK | + CS35L45_ASP_FSYNC_INV_MASK | + CS35L45_ASP_BCLK_INV_MASK, + (asp_fmt << CS35L45_ASP_FMT_SHIFT) | + (fsync_inv << CS35L45_ASP_FSYNC_INV_SHIFT) | + (bclk_inv << CS35L45_ASP_BCLK_INV_SHIFT)); + + return 0; +} + +static int cs35l45_asp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); + unsigned int asp_width, asp_wl, global_fs, slot_multiple, asp_fmt; + int bclk; + + switch (params_rate(params)) { + case 44100: + global_fs = CS35L45_44P100_KHZ; + break; + case 48000: + global_fs = CS35L45_48P0_KHZ; + break; + case 88200: + global_fs = CS35L45_88P200_KHZ; + break; + case 96000: + global_fs = CS35L45_96P0_KHZ; + break; + default: + dev_warn(cs35l45->dev, "Unsupported sample rate (%d)\n", + params_rate(params)); + return -EINVAL; + } + + regmap_update_bits(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, + CS35L45_GLOBAL_FS_MASK, + global_fs << CS35L45_GLOBAL_FS_SHIFT); + + asp_wl = params_width(params); + + if (cs35l45->slot_width) + asp_width = cs35l45->slot_width; + else + asp_width = params_width(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, + CS35L45_ASP_WIDTH_RX_MASK, + asp_width << CS35L45_ASP_WIDTH_RX_SHIFT); + + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL5, + CS35L45_ASP_WL_MASK, + asp_wl << CS35L45_ASP_WL_SHIFT); + } else { + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL2, + CS35L45_ASP_WIDTH_TX_MASK, + asp_width << CS35L45_ASP_WIDTH_TX_SHIFT); + + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_DATA_CONTROL1, + CS35L45_ASP_WL_MASK, + asp_wl << CS35L45_ASP_WL_SHIFT); + } + + if (cs35l45->sysclk_set) + return 0; + + /* I2S always has an even number of channels */ + regmap_read(cs35l45->regmap, CS35L45_ASP_CONTROL2, &asp_fmt); + asp_fmt = (asp_fmt & CS35L45_ASP_FMT_MASK) >> CS35L45_ASP_FMT_SHIFT; + if (asp_fmt == CS35L45_ASP_FMT_I2S) + slot_multiple = 2; + else + slot_multiple = 1; + + bclk = snd_soc_tdm_params_to_bclk(params, asp_width, + cs35l45->slot_count, slot_multiple); + + return cs35l45_set_pll(cs35l45, bclk); +} + +static int cs35l45_asp_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); + + if (slot_width && ((slot_width < 16) || (slot_width > 128))) + return -EINVAL; + + cs35l45->slot_width = slot_width; + cs35l45->slot_count = slots; + + return 0; +} + +static int cs35l45_asp_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); + int ret; + + if (clk_id != 0) { + dev_err(cs35l45->dev, "Invalid clk_id %d\n", clk_id); + return -EINVAL; + } + + cs35l45->sysclk_set = false; + if (freq == 0) + return 0; + + ret = cs35l45_set_pll(cs35l45, freq); + if (ret < 0) + return -EINVAL; + + cs35l45->sysclk_set = true; + + return 0; +} + +static int cs35l45_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(dai->component); + unsigned int global_fs, val, hpf_tune; + + if (mute) + return 0; + + regmap_read(cs35l45->regmap, CS35L45_GLOBAL_SAMPLE_RATE, &global_fs); + global_fs = (global_fs & CS35L45_GLOBAL_FS_MASK) >> CS35L45_GLOBAL_FS_SHIFT; + switch (global_fs) { + case CS35L45_44P100_KHZ: + hpf_tune = CS35L45_HPF_44P1; + break; + case CS35L45_88P200_KHZ: + hpf_tune = CS35L45_HPF_88P2; + break; + default: + hpf_tune = CS35l45_HPF_DEFAULT; + break; + } + + regmap_read(cs35l45->regmap, CS35L45_AMP_PCM_HPF_TST, &val); + if (val != hpf_tune) { + struct reg_sequence hpf_override_seq[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00000044, 0x00000055 }, + { 0x00000044, 0x000000AA }, + { CS35L45_AMP_PCM_HPF_TST, hpf_tune }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000000 }, + }; + regmap_multi_reg_write(cs35l45->regmap, hpf_override_seq, + ARRAY_SIZE(hpf_override_seq)); + } + + return 0; +} + +static const struct snd_soc_dai_ops cs35l45_asp_dai_ops = { + .set_fmt = cs35l45_asp_set_fmt, + .hw_params = cs35l45_asp_hw_params, + .set_tdm_slot = cs35l45_asp_set_tdm_slot, + .set_sysclk = cs35l45_asp_set_sysclk, + .mute_stream = cs35l45_mute_stream, +}; + +static struct snd_soc_dai_driver cs35l45_dai[] = { + { + .name = "cs35l45", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS35L45_RATES, + .formats = CS35L45_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 5, + .rates = CS35L45_RATES, + .formats = CS35L45_FORMATS, + }, + .symmetric_rate = true, + .symmetric_sample_bits = true, + .ops = &cs35l45_asp_dai_ops, + }, +}; + +static const struct snd_soc_component_driver cs35l45_component = { + .dapm_widgets = cs35l45_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets), + + .dapm_routes = cs35l45_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes), + + .controls = cs35l45_controls, + .num_controls = ARRAY_SIZE(cs35l45_controls), + + .name = "cs35l45", + + .endianness = 1, +}; + +static int __maybe_unused cs35l45_runtime_suspend(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l45->regmap, true); + + dev_dbg(cs35l45->dev, "Runtime suspended\n"); + + return 0; +} + +static int __maybe_unused cs35l45_runtime_resume(struct device *dev) +{ + struct cs35l45_private *cs35l45 = dev_get_drvdata(dev); + int ret; + + dev_dbg(cs35l45->dev, "Runtime resume\n"); + + regcache_cache_only(cs35l45->regmap, false); + ret = regcache_sync(cs35l45->regmap); + if (ret != 0) + dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret); + + /* Clear global error status */ + regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); + regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); + regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK); + return ret; +} + +static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45) +{ + unsigned int val; + + if (device_property_read_u32(cs35l45->dev, + "cirrus,asp-sdout-hiz-ctrl", &val) == 0) { + regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3, + CS35L45_ASP_DOUT_HIZ_CTRL_MASK, + val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT); + } + + return 0; +} + +static int cs35l45_initialize(struct cs35l45_private *cs35l45) +{ + struct device *dev = cs35l45->dev; + unsigned int dev_id[5]; + unsigned int sts; + int ret; + + ret = regmap_read_poll_timeout(cs35l45->regmap, CS35L45_IRQ1_EINT_4, sts, + (sts & CS35L45_OTP_BOOT_DONE_STS_MASK), + 1000, 5000); + if (ret < 0) { + dev_err(cs35l45->dev, "Timeout waiting for OTP boot\n"); + return ret; + } + + ret = regmap_bulk_read(cs35l45->regmap, CS35L45_DEVID, dev_id, ARRAY_SIZE(dev_id)); + if (ret) { + dev_err(cs35l45->dev, "Get Device ID failed: %d\n", ret); + return ret; + } + + switch (dev_id[0]) { + case 0x35A450: + break; + default: + dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]); + return -ENODEV; + } + + dev_info(cs35l45->dev, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n", + dev_id[1], dev_id[4]); + + regmap_write(cs35l45->regmap, CS35L45_IRQ1_EINT_4, + CS35L45_OTP_BOOT_DONE_STS_MASK | CS35L45_OTP_BUSY_MASK); + + ret = cs35l45_apply_patch(cs35l45); + if (ret < 0) { + dev_err(dev, "Failed to apply init patch %d\n", ret); + return ret; + } + + ret = cs35l45_apply_property_config(cs35l45); + if (ret < 0) + return ret; + + pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000); + pm_runtime_use_autosuspend(cs35l45->dev); + pm_runtime_set_active(cs35l45->dev); + pm_runtime_enable(cs35l45->dev); + + return 0; +} + +int cs35l45_probe(struct cs35l45_private *cs35l45) +{ + struct device *dev = cs35l45->dev; + int ret; + + cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt"); + if (IS_ERR(cs35l45->vdd_batt)) + return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_batt), + "Failed to request vdd-batt\n"); + + cs35l45->vdd_a = devm_regulator_get(dev, "vdd-a"); + if (IS_ERR(cs35l45->vdd_a)) + return dev_err_probe(dev, PTR_ERR(cs35l45->vdd_a), + "Failed to request vdd-a\n"); + + /* VDD_BATT must always be enabled before other supplies */ + ret = regulator_enable(cs35l45->vdd_batt); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable vdd-batt\n"); + + ret = regulator_enable(cs35l45->vdd_a); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable vdd-a\n"); + + /* If reset is shared only one instance can claim it */ + cs35l45->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs35l45->reset_gpio)) { + ret = PTR_ERR(cs35l45->reset_gpio); + cs35l45->reset_gpio = NULL; + if (ret == -EBUSY) { + dev_dbg(dev, "Reset line busy, assuming shared reset\n"); + } else { + dev_err_probe(dev, ret, "Failed to get reset GPIO\n"); + goto err; + } + } + + if (cs35l45->reset_gpio) { + usleep_range(CS35L45_RESET_HOLD_US, CS35L45_RESET_HOLD_US + 100); + gpiod_set_value_cansleep(cs35l45->reset_gpio, 1); + } + + usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100); + + ret = cs35l45_initialize(cs35l45); + if (ret < 0) + goto err_reset; + + ret = devm_snd_soc_register_component(dev, &cs35l45_component, + cs35l45_dai, + ARRAY_SIZE(cs35l45_dai)); + if (ret < 0) + goto err_reset; + + return 0; + +err_reset: + gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); +err: + regulator_disable(cs35l45->vdd_a); + regulator_disable(cs35l45->vdd_batt); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45); + +void cs35l45_remove(struct cs35l45_private *cs35l45) +{ + pm_runtime_disable(cs35l45->dev); + + gpiod_set_value_cansleep(cs35l45->reset_gpio, 0); + regulator_disable(cs35l45->vdd_a); + /* VDD_BATT must be the last to power-off */ + regulator_disable(cs35l45->vdd_batt); +} +EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); + +const struct dev_pm_ops cs35l45_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) +}; +EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45); + +MODULE_DESCRIPTION("ASoC CS35L45 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_CS35L45_TABLES); diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h new file mode 100644 index 000000000000..53fe9d2b7b15 --- /dev/null +++ b/sound/soc/codecs/cs35l45.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * cs35l45.h - CS35L45 ALSA SoC audio driver + * + * Copyright 2019-2022 Cirrus Logic, Inc. + * + * Author: James Schulman <james.schulman@cirrus.com> + * + */ + +#ifndef CS35L45_H +#define CS35L45_H + +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define CS35L45_DEVID 0x00000000 +#define CS35L45_REVID 0x00000004 +#define CS35L45_RELID 0x0000000C +#define CS35L45_OTPID 0x00000010 +#define CS35L45_SFT_RESET 0x00000020 +#define CS35L45_GLOBAL_ENABLES 0x00002014 +#define CS35L45_BLOCK_ENABLES 0x00002018 +#define CS35L45_BLOCK_ENABLES2 0x0000201C +#define CS35L45_ERROR_RELEASE 0x00002034 +#define CS35L45_REFCLK_INPUT 0x00002C04 +#define CS35L45_GLOBAL_SAMPLE_RATE 0x00002C0C +#define CS35L45_BOOST_CCM_CFG 0x00003808 +#define CS35L45_BOOST_DCM_CFG 0x0000380C +#define CS35L45_BOOST_OV_CFG 0x0000382C +#define CS35L45_ASP_ENABLES1 0x00004800 +#define CS35L45_ASP_CONTROL1 0x00004804 +#define CS35L45_ASP_CONTROL2 0x00004808 +#define CS35L45_ASP_CONTROL3 0x0000480C +#define CS35L45_ASP_FRAME_CONTROL1 0x00004810 +#define CS35L45_ASP_FRAME_CONTROL2 0x00004814 +#define CS35L45_ASP_FRAME_CONTROL5 0x00004820 +#define CS35L45_ASP_DATA_CONTROL1 0x00004830 +#define CS35L45_ASP_DATA_CONTROL5 0x00004840 +#define CS35L45_DACPCM1_INPUT 0x00004C00 +#define CS35L45_ASPTX1_INPUT 0x00004C20 +#define CS35L45_ASPTX2_INPUT 0x00004C24 +#define CS35L45_ASPTX3_INPUT 0x00004C28 +#define CS35L45_ASPTX4_INPUT 0x00004C2C +#define CS35L45_ASPTX5_INPUT 0x00004C30 +#define CS35L45_LDPM_CONFIG 0x00006404 +#define CS35L45_AMP_PCM_CONTROL 0x00007000 +#define CS35L45_AMP_PCM_HPF_TST 0x00007004 +#define CS35L45_IRQ1_EINT_4 0x0000E01C +#define CS35L45_LASTREG 0x0000E01C + +/* SFT_RESET */ +#define CS35L45_SOFT_RESET_TRIGGER 0x5A000000 + +/* GLOBAL_ENABLES */ +#define CS35L45_GLOBAL_EN_SHIFT 0 +#define CS35L45_GLOBAL_EN_MASK BIT(0) + +/* BLOCK_ENABLES */ +#define CS35L45_IMON_EN_SHIFT 13 +#define CS35L45_VMON_EN_SHIFT 12 +#define CS35L45_VDD_BSTMON_EN_SHIFT 9 +#define CS35L45_VDD_BATTMON_EN_SHIFT 8 +#define CS35L45_BST_EN_SHIFT 4 +#define CS35L45_BST_EN_MASK GENMASK(5, 4) + +#define CS35L45_BST_DISABLE_FET_ON 0x01 + +/* BLOCK_ENABLES2 */ +#define CS35L45_ASP_EN_SHIFT 27 + +/* ERROR_RELEASE */ +#define CS35L45_GLOBAL_ERR_RLS_MASK BIT(11) + +/* REFCLK_INPUT */ +#define CS35L45_PLL_FORCE_EN_SHIFT 16 +#define CS35L45_PLL_FORCE_EN_MASK BIT(16) +#define CS35L45_PLL_OPEN_LOOP_SHIFT 11 +#define CS35L45_PLL_OPEN_LOOP_MASK BIT(11) +#define CS35L45_PLL_REFCLK_FREQ_SHIFT 5 +#define CS35L45_PLL_REFCLK_FREQ_MASK GENMASK(10, 5) +#define CS35L45_PLL_REFCLK_EN_SHIFT 4 +#define CS35L45_PLL_REFCLK_EN_MASK BIT(4) +#define CS35L45_PLL_REFCLK_SEL_SHIFT 0 +#define CS35L45_PLL_REFCLK_SEL_MASK GENMASK(2, 0) + +#define CS35L45_PLL_REFCLK_SEL_BCLK 0x0 + +/* GLOBAL_SAMPLE_RATE */ +#define CS35L45_GLOBAL_FS_SHIFT 0 +#define CS35L45_GLOBAL_FS_MASK GENMASK(4, 0) + +#define CS35L45_48P0_KHZ 0x03 +#define CS35L45_96P0_KHZ 0x04 +#define CS35L45_44P100_KHZ 0x0B +#define CS35L45_88P200_KHZ 0x0C + +/* ASP_ENABLES_1 */ +#define CS35L45_ASP_RX2_EN_SHIFT 17 +#define CS35L45_ASP_RX1_EN_SHIFT 16 +#define CS35L45_ASP_TX5_EN_SHIFT 4 +#define CS35L45_ASP_TX4_EN_SHIFT 3 +#define CS35L45_ASP_TX3_EN_SHIFT 2 +#define CS35L45_ASP_TX2_EN_SHIFT 1 +#define CS35L45_ASP_TX1_EN_SHIFT 0 + +/* ASP_CONTROL2 */ +#define CS35L45_ASP_WIDTH_RX_SHIFT 24 +#define CS35L45_ASP_WIDTH_RX_MASK GENMASK(31, 24) +#define CS35L45_ASP_WIDTH_TX_SHIFT 16 +#define CS35L45_ASP_WIDTH_TX_MASK GENMASK(23, 16) +#define CS35L45_ASP_FMT_SHIFT 8 +#define CS35L45_ASP_FMT_MASK GENMASK(10, 8) +#define CS35L45_ASP_BCLK_INV_SHIFT 6 +#define CS35L45_ASP_BCLK_INV_MASK BIT(6) +#define CS35L45_ASP_FSYNC_INV_SHIFT 2 +#define CS35L45_ASP_FSYNC_INV_MASK BIT(2) + +#define CS35l45_ASP_FMT_DSP_A 0 +#define CS35L45_ASP_FMT_I2S 2 + +/* ASP_CONTROL3 */ +#define CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT 0 +#define CS35L45_ASP_DOUT_HIZ_CTRL_MASK GENMASK(1, 0) + +/* ASP_FRAME_CONTROL1 */ +#define CS35L45_ASP_TX4_SLOT_SHIFT 24 +#define CS35L45_ASP_TX4_SLOT_MASK GENMASK(29, 24) +#define CS35L45_ASP_TX3_SLOT_SHIFT 16 +#define CS35L45_ASP_TX3_SLOT_MASK GENMASK(21, 16) +#define CS35L45_ASP_TX2_SLOT_SHIFT 8 +#define CS35L45_ASP_TX2_SLOT_MASK GENMASK(13, 8) +#define CS35L45_ASP_TX1_SLOT_SHIFT 0 +#define CS35L45_ASP_TX1_SLOT_MASK GENMASK(5, 0) + +#define CS35L45_ASP_TX_ALL_SLOTS (CS35L45_ASP_TX4_SLOT_MASK | \ + CS35L45_ASP_TX3_SLOT_MASK | \ + CS35L45_ASP_TX2_SLOT_MASK | \ + CS35L45_ASP_TX1_SLOT_MASK) +/* ASP_FRAME_CONTROL5 */ +#define CS35L45_ASP_RX2_SLOT_SHIFT 8 +#define CS35L45_ASP_RX2_SLOT_MASK GENMASK(13, 8) +#define CS35L45_ASP_RX1_SLOT_SHIFT 0 +#define CS35L45_ASP_RX1_SLOT_MASK GENMASK(5, 0) + +#define CS35L45_ASP_RX_ALL_SLOTS (CS35L45_ASP_RX2_SLOT_MASK | \ + CS35L45_ASP_RX1_SLOT_MASK) + +/* ASP_DATA_CONTROL1 */ +/* ASP_DATA_CONTROL5 */ +#define CS35L45_ASP_WL_SHIFT 0 +#define CS35L45_ASP_WL_MASK GENMASK(5, 0) + +/* AMP_PCM_CONTROL */ +#define CS35L45_AMP_VOL_PCM_SHIFT 0 +#define CS35L45_AMP_VOL_PCM_WIDTH 11 + +/* AMP_PCM_HPF_TST */ +#define CS35l45_HPF_DEFAULT 0x00000000 +#define CS35L45_HPF_44P1 0x000108BD +#define CS35L45_HPF_88P2 0x0001045F + +/* IRQ1_EINT_4 */ +#define CS35L45_OTP_BOOT_DONE_STS_MASK BIT(1) +#define CS35L45_OTP_BUSY_MASK BIT(0) + +/* Mixer sources */ +#define CS35L45_PCM_SRC_MASK 0x7F +#define CS35L45_PCM_SRC_ZERO 0x00 +#define CS35L45_PCM_SRC_ASP_RX1 0x08 +#define CS35L45_PCM_SRC_ASP_RX2 0x09 +#define CS35L45_PCM_SRC_VMON 0x18 +#define CS35L45_PCM_SRC_IMON 0x19 +#define CS35L45_PCM_SRC_ERR_VOL 0x20 +#define CS35L45_PCM_SRC_CLASSH_TGT 0x21 +#define CS35L45_PCM_SRC_VDD_BATTMON 0x28 +#define CS35L45_PCM_SRC_VDD_BSTMON 0x29 +#define CS35L45_PCM_SRC_TEMPMON 0x3A +#define CS35L45_PCM_SRC_INTERPOLATOR 0x40 +#define CS35L45_PCM_SRC_IL_TARGET 0x48 + +#define CS35L45_RESET_HOLD_US 2000 +#define CS35L45_RESET_US 2000 +#define CS35L45_POST_GLOBAL_EN_US 5000 +#define CS35L45_PRE_GLOBAL_DIS_US 3000 + +#define CS35L45_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE| \ + SNDRV_PCM_FMTBIT_S24_LE) + +#define CS35L45_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000) + +struct cs35l45_private { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + struct regulator *vdd_batt; + struct regulator *vdd_a; + bool initialized; + bool sysclk_set; + u8 slot_width; + u8 slot_count; +}; + +extern const struct dev_pm_ops cs35l45_pm_ops; +extern const struct regmap_config cs35l45_i2c_regmap; +extern const struct regmap_config cs35l45_spi_regmap; +int cs35l45_apply_patch(struct cs35l45_private *cs35l45); +unsigned int cs35l45_get_clk_freq_id(unsigned int freq); +int cs35l45_probe(struct cs35l45_private *cs35l45); +void cs35l45_remove(struct cs35l45_private *cs35l45); + +#endif /* CS35L45_H */ diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c index 20126cc675b1..dee1a6662c2e 100644 --- a/sound/soc/codecs/cs4234.c +++ b/sound/soc/codecs/cs4234.c @@ -660,9 +660,9 @@ static const struct snd_soc_component_driver soc_component_cs4234 = { .controls = cs4234_snd_controls, .num_controls = ARRAY_SIZE(cs4234_snd_controls), .set_bias_level = cs4234_set_bias_level, - .non_legacy_dai_naming = 1, .idle_bias_on = 1, .suspend_bias_off = 1, + .endianness = 1, }; static const struct regmap_config cs4234_regmap = { @@ -731,7 +731,7 @@ static int cs4234_powerup(struct cs4234 *cs4234) return 0; } -static int cs4234_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) +static int cs4234_i2c_probe(struct i2c_client *i2c_client) { struct cs4234 *cs4234; struct device *dev = &i2c_client->dev; @@ -850,7 +850,7 @@ fail_shutdown: return ret; } -static int cs4234_i2c_remove(struct i2c_client *i2c_client) +static void cs4234_i2c_remove(struct i2c_client *i2c_client) { struct cs4234 *cs4234 = i2c_get_clientdata(i2c_client); struct device *dev = &i2c_client->dev; @@ -858,8 +858,6 @@ static int cs4234_i2c_remove(struct i2c_client *i2c_client) snd_soc_unregister_component(dev); pm_runtime_disable(dev); cs4234_shutdown(cs4234); - - return 0; } static int __maybe_unused cs4234_runtime_resume(struct device *dev) @@ -908,7 +906,7 @@ static struct i2c_driver cs4234_i2c_driver = { .pm = &cs4234_pm, .of_match_table = cs4234_of_match, }, - .probe = cs4234_i2c_probe, + .probe_new = cs4234_i2c_probe, .remove = cs4234_i2c_remove, }; module_i2c_driver(cs4234_i2c_driver); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index cffd6111afac..3573363b7e31 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -150,7 +150,6 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, 6, 1, 0), SOC_ENUM("C Data Access", cam_mode_enum), - SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1), SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), @@ -186,7 +185,7 @@ static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0, &loopback_ctl), - SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SWITCH("SPDIF", CS4265_SPDIF_CTL2, 5, 1, &spdif_switch), SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1, &dac_switch), @@ -554,7 +553,6 @@ static const struct snd_soc_component_driver soc_component_cs4265 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs4265_regmap = { @@ -569,8 +567,7 @@ static const struct regmap_config cs4265_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs4265_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs4265_i2c_probe(struct i2c_client *i2c_client) { struct cs4265_private *cs4265; int ret; @@ -611,8 +608,8 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, if (devid != CS4265_CHIP_ID_VAL) { ret = -ENODEV; dev_err(&i2c_client->dev, - "CS4265 Device ID (%X). Expected %X\n", - devid, CS4265_CHIP_ID); + "CS4265 Part Number ID: 0x%x Expected: 0x%x\n", + devid >> 4, CS4265_CHIP_ID_VAL >> 4); return ret; } dev_info(&i2c_client->dev, @@ -626,6 +623,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, ARRAY_SIZE(cs4265_dai)); } +static void cs4265_i2c_remove(struct i2c_client *i2c) +{ + struct cs4265_private *cs4265 = i2c_get_clientdata(i2c); + + if (cs4265->reset_gpio) + gpiod_set_value_cansleep(cs4265->reset_gpio, 0); +} + static const struct of_device_id cs4265_of_match[] = { { .compatible = "cirrus,cs4265", }, { } @@ -644,7 +649,8 @@ static struct i2c_driver cs4265_i2c_driver = { .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, - .probe = cs4265_i2c_probe, + .probe_new = cs4265_i2c_probe, + .remove = cs4265_i2c_remove, }; module_i2c_driver(cs4265_i2c_driver); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 2d239e983a83..1b640d8232ba 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -32,18 +32,9 @@ #include <linux/gpio/consumer.h> #include <linux/of_device.h> -/* - * The codec isn't really big-endian or little-endian, since the I2S - * interface requires data to be sent serially with the MSbit first. - * However, to support BE and LE I2S devices, we specify both here. That - * way, ALSA will always match the bit patterns. - */ -#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) /* CS4270 registers addresses */ #define CS4270_CHIPID 0x01 /* Chip ID */ @@ -628,7 +619,6 @@ static const struct snd_soc_component_driver soc_component_device_cs4270 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* @@ -660,25 +650,21 @@ static const struct regmap_config cs4270_regmap = { * This function puts the chip into low power mode when the i2c device * is removed. */ -static int cs4270_i2c_remove(struct i2c_client *i2c_client) +static void cs4270_i2c_remove(struct i2c_client *i2c_client) { struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client); gpiod_set_value_cansleep(cs4270->reset_gpio, 0); - - return 0; } /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object - * @id: the I2C device ID (ignored) * * This function is called whenever the I2C subsystem finds a device that * matches the device ID given via a prior call to i2c_add_driver(). */ -static int cs4270_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs4270_i2c_probe(struct i2c_client *i2c_client) { struct cs4270_private *cs4270; unsigned int val; @@ -765,7 +751,7 @@ static struct i2c_driver cs4270_i2c_driver = { .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, - .probe = cs4270_i2c_probe, + .probe_new = cs4270_i2c_probe, .remove = cs4270_i2c_remove, }; diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c index 0a174236f573..0e8a7cf0da50 100644 --- a/sound/soc/codecs/cs4271-i2c.c +++ b/sound/soc/codecs/cs4271-i2c.c @@ -11,8 +11,7 @@ #include <sound/soc.h> #include "cs4271.h" -static int cs4271_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs4271_i2c_probe(struct i2c_client *client) { struct regmap_config config; @@ -35,7 +34,7 @@ static struct i2c_driver cs4271_i2c_driver = { .name = "cs4271", .of_match_table = of_match_ptr(cs4271_dt_ids), }, - .probe = cs4271_i2c_probe, + .probe_new = cs4271_i2c_probe, .id_table = cs4271_i2c_id, }; module_i2c_driver(cs4271_i2c_driver); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 7663f89ac6a2..2021cf442606 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -642,7 +642,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4271 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs4271_common_probe(struct device *dev, diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c new file mode 100644 index 000000000000..67b253287daf --- /dev/null +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l42-i2c.c -- CS42L42 ALSA SoC audio driver for I2C + * + * Copyright 2016, 2022 Cirrus Logic, Inc. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "cs42l42.h" + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client) +{ + struct device *dev = &i2c_client->dev; + struct cs42l42_private *cs42l42; + struct regmap *regmap; + int ret; + + cs42l42 = devm_kzalloc(dev, sizeof(*cs42l42), GFP_KERNEL); + if (!cs42l42) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap), + "regmap_init() failed\n"); + + cs42l42->devid = CS42L42_CHIP_ID; + cs42l42->dev = dev; + cs42l42->regmap = regmap; + cs42l42->irq = i2c_client->irq; + + ret = cs42l42_common_probe(cs42l42, &cs42l42_soc_component, &cs42l42_dai); + if (ret) + return ret; + + return cs42l42_init(cs42l42); +} + +static void cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(&i2c_client->dev); + + cs42l42_common_remove(cs42l42); +} + +static int __maybe_unused cs42l42_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); + + return 0; +} + +static const struct dev_pm_ops cs42l42_i2c_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) +}; + +static const struct of_device_id __maybe_unused cs42l42_of_match[] = { + { .compatible = "cirrus,cs42l42", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l42_of_match); + +static const struct acpi_device_id __maybe_unused cs42l42_acpi_match[] = { + {"10134242", 0,}, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match); + +static const struct i2c_device_id cs42l42_id[] = { + {"cs42l42", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l42_id); + +static struct i2c_driver cs42l42_i2c_driver = { + .driver = { + .name = "cs42l42", + .pm = &cs42l42_i2c_pm_ops, + .of_match_table = of_match_ptr(cs42l42_of_match), + .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), + }, + .id_table = cs42l42_id, + .probe_new = cs42l42_i2c_probe, + .remove = cs42l42_i2c_remove, +}; + +module_i2c_driver(cs42l42_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L42 I2C driver"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 27a1c4c73074..2fefbcf7bd13 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -12,10 +12,9 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/version.h> -#include <linux/kernel.h> +#include <linux/types.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/i2c.h> #include <linux/gpio.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -37,11 +36,20 @@ #include "cs42l42.h" #include "cirrus_legacy.h" +static const char * const cs42l42_supply_names[] = { + "VA", + "VP", + "VCP", + "VD_FILT", + "VL", +}; + static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_FRZ_CTL, 0x00 }, { CS42L42_SRC_CTL, 0x10 }, { CS42L42_MCLK_CTL, 0x02 }, { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_SLOW_START_ENABLE, 0x70 }, { CS42L42_I2C_DEBOUNCE, 0x88 }, { CS42L42_I2C_STRETCH, 0x03 }, { CS42L42_I2C_TIMEOUT, 0xB7 }, @@ -163,7 +171,7 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, }; -static bool cs42l42_readable_register(struct device *dev, unsigned int reg) +bool cs42l42_readable_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_PAGE_REGISTER: @@ -177,6 +185,7 @@ static bool cs42l42_readable_register(struct device *dev, unsigned int reg) case CS42L42_MCLK_STATUS: case CS42L42_MCLK_CTL: case CS42L42_SFTRAMP_RATE: + case CS42L42_SLOW_START_ENABLE: case CS42L42_I2C_DEBOUNCE: case CS42L42_I2C_STRETCH: case CS42L42_I2C_TIMEOUT: @@ -321,8 +330,9 @@ static bool cs42l42_readable_register(struct device *dev, unsigned int reg) return false; } } +EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE); -static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) +bool cs42l42_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_DEVID_AB: @@ -353,8 +363,9 @@ static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) return false; } } +EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE); -static const struct regmap_range_cfg cs42l42_page_range = { +const struct regmap_range_cfg cs42l42_page_range = { .name = "Pages", .range_min = 0, .range_max = CS42L42_MAX_REGISTER, @@ -364,8 +375,9 @@ static const struct regmap_range_cfg cs42l42_page_range = { .window_start = 0, .window_len = 256, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE); -static const struct regmap_config cs42l42_regmap = { +const struct regmap_config cs42l42_regmap = { .reg_bits = 8, .val_bits = 8, @@ -383,10 +395,33 @@ static const struct regmap_config cs42l42_regmap = { .use_single_read = true, .use_single_write = true, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE); static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true); static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); +static int cs42l42_slow_start_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + u8 val; + + /* all bits of SLOW_START_EN must change together */ + switch (ucontrol->value.integer.value[0]) { + case 0: + val = 0; + break; + case 1: + val = CS42L42_SLOW_START_EN_MASK; + break; + default: + return -EINVAL; + } + + return snd_soc_component_update_bits(component, CS42L42_SLOW_START_ENABLE, + CS42L42_SLOW_START_EN_MASK, val); +} + static const char * const cs42l42_hpf_freq_text[] = { "1.86Hz", "120Hz", "235Hz", "466Hz" }; @@ -431,7 +466,11 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = { CS42L42_DAC_HPF_EN_SHIFT, true, false), SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, - 0x3f, 1, mixer_tlv) + 0x3f, 1, mixer_tlv), + + SOC_SINGLE_EXT("Slow Start Switch", CS42L42_SLOW_START_ENABLE, + CS42L42_SLOW_START_EN_SHIFT, true, false, + snd_soc_get_volsw, cs42l42_slow_start_put), }; static int cs42l42_hp_adc_ev(struct snd_soc_dapm_widget *w, @@ -521,12 +560,29 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + /* Prevent race with interrupt handler */ + mutex_lock(&cs42l42->irq_lock); cs42l42->jack = jk; + if (jk) { + switch (cs42l42->hs_type) { + case CS42L42_PLUG_CTIA: + case CS42L42_PLUG_OMTP: + snd_soc_jack_report(jk, SND_JACK_HEADSET, SND_JACK_HEADSET); + break; + case CS42L42_PLUG_HEADPHONE: + snd_soc_jack_report(jk, SND_JACK_HEADPHONE, SND_JACK_HEADPHONE); + break; + default: + break; + } + } + mutex_unlock(&cs42l42->irq_lock); + return 0; } -static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { +const struct snd_soc_component_driver cs42l42_soc_component = { .set_jack = cs42l42_set_jack, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), @@ -536,8 +592,8 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .num_controls = ARRAY_SIZE(cs42l42_snd_controls), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE); /* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */ static const struct reg_sequence cs42l42_to_sclk_seq[] = { @@ -595,18 +651,12 @@ static const struct cs42l42_pll_params pll_ratio_table[] = { { 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1} }; -static int cs42l42_pll_config(struct snd_soc_component *component) +static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk) { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); int i; - u32 clk; u32 fsync; - if (!cs42l42->sclk) - clk = cs42l42->bclk; - else - clk = cs42l42->sclk; - /* Don't reconfigure if there is an audio stream running */ if (cs42l42->stream_use) { if (pll_ratio_table[cs42l42->pll_config].sclk == clk) @@ -706,10 +756,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component) CS42L42_PLL_DIVOUT_MASK, (pll_ratio_table[i].pll_divout * pll_ratio_table[i].n) << CS42L42_PLL_DIVOUT_SHIFT); - if (pll_ratio_table[i].n != 1) - cs42l42->pll_divout = pll_ratio_table[i].pll_divout; - else - cs42l42->pll_divout = 0; snd_soc_component_update_bits(component, CS42L42_PLL_CAL_RATIO, CS42L42_PLL_CAL_RATIO_MASK, @@ -845,22 +891,30 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int channels = params_channels(params); unsigned int width = (params_width(params) / 8) - 1; + unsigned int slot_width = 0; unsigned int val = 0; + unsigned int bclk; int ret; cs42l42->srate = params_rate(params); - cs42l42->bclk = snd_soc_params_to_bclk(params); - /* I2S frame always has 2 channels even for mono audio */ - if (channels == 1) - cs42l42->bclk *= 2; + if (cs42l42->bclk_ratio) { + /* machine driver has set the BCLK/samp-rate ratio */ + bclk = cs42l42->bclk_ratio * params_rate(params); + } else if (cs42l42->sclk) { + /* machine driver has set the SCLK */ + bclk = cs42l42->sclk; + } else { + /* + * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being + * more than assumed (which would result in overclocking). + */ + if (params_width(params) == 24) + slot_width = 32; - /* - * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being - * more than assumed (which would result in overclocking). - */ - if (params_width(params) == 24) - cs42l42->bclk = (cs42l42->bclk / 3) * 4; + /* I2S frame always has multiple of 2 channels */ + bclk = snd_soc_tdm_params_to_bclk(params, slot_width, 0, 2); + } switch (substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: @@ -900,7 +954,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, break; } - ret = cs42l42_pll_config(component); + ret = cs42l42_pll_config(component, bclk); if (ret) return ret; @@ -933,6 +987,17 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai, return -EINVAL; } +static int cs42l42_set_bclk_ratio(struct snd_soc_dai *dai, + unsigned int bclk_ratio) +{ + struct snd_soc_component *component = dai->component; + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + + cs42l42->bclk_ratio = bclk_ratio; + + return 0; +} + static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; @@ -971,17 +1036,25 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) } } else { if (!cs42l42->stream_use) { - /* SCLK must be running before codec unmute */ + /* SCLK must be running before codec unmute. + * + * PLL must not be started with ADC and HP both off + * otherwise the FILT+ supply will not charge properly. + * DAPM widgets power-up before stream unmute so at least + * one of the "DAC" or "ADC" widgets will already have + * powered-up. + */ if (pll_ratio_table[cs42l42->pll_config].mclk_src_sel) { snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 1); - if (cs42l42->pll_divout) { + if (pll_ratio_table[cs42l42->pll_config].n > 1) { usleep_range(CS42L42_PLL_DIVOUT_TIME_US, CS42L42_PLL_DIVOUT_TIME_US * 2); + regval = pll_ratio_table[cs42l42->pll_config].pll_divout; snd_soc_component_update_bits(component, CS42L42_PLL_CTL3, CS42L42_PLL_DIVOUT_MASK, - cs42l42->pll_divout << + regval << CS42L42_PLL_DIVOUT_SHIFT); } @@ -1028,10 +1101,11 @@ static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, + .set_bclk_ratio = cs42l42_set_bclk_ratio, .mute_stream = cs42l42_mute_stream, }; -static struct snd_soc_dai_driver cs42l42_dai = { +struct snd_soc_dai_driver cs42l42_dai = { .name = "cs42l42", .playback = { .stream_name = "Playback", @@ -1051,6 +1125,7 @@ static struct snd_soc_dai_driver cs42l42_dai = { .symmetric_sample_bits = 1, .ops = &cs42l42_ops, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE); static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) { @@ -1124,14 +1199,11 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) cs42l42->hs_type = CS42L42_PLUG_OMTP; hs_det_sw = CS42L42_HSDET_SW_TYPE2; break; - case CS42L42_HSDET_COMP_TYPE3: + /* Detect Type 3 and Type 4 Headsets as Headphones */ + default: cs42l42->hs_type = CS42L42_PLUG_HEADPHONE; hs_det_sw = CS42L42_HSDET_SW_TYPE3; break; - default: - cs42l42->hs_type = CS42L42_PLUG_INVALID; - hs_det_sw = CS42L42_HSDET_SW_TYPE4; - break; } } @@ -1242,10 +1314,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Turn on level detect circuitry */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (3 << CS42L42_HSBIAS_CTL_SHIFT) | (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1272,10 +1342,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Make sure button detect and HS bias circuits are off */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); } @@ -1296,12 +1364,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Unmask tip sense interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, - CS42L42_RS_PLUG_MASK | - CS42L42_RS_UNPLUG_MASK | CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, - (1 << CS42L42_RS_PLUG_SHIFT) | - (1 << CS42L42_RS_UNPLUG_SHIFT) | (0 << CS42L42_TS_PLUG_SHIFT) | (0 << CS42L42_TS_UNPLUG_SHIFT)); } @@ -1311,22 +1375,16 @@ static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) /* Mask tip sense interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, - CS42L42_RS_PLUG_MASK | - CS42L42_RS_UNPLUG_MASK | CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, - (1 << CS42L42_RS_PLUG_SHIFT) | - (1 << CS42L42_RS_UNPLUG_SHIFT) | (1 << CS42L42_TS_PLUG_SHIFT) | (1 << CS42L42_TS_UNPLUG_SHIFT)); /* Make sure button detect and HS bias circuits are off */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1370,10 +1428,8 @@ static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) /* Power up HS bias to 2.7V */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (3 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1420,10 +1476,8 @@ static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) /* Ground HS bias */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1587,8 +1641,12 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int current_plug_status; unsigned int current_button_status; unsigned int i; - int report = 0; + mutex_lock(&cs42l42->irq_lock); + if (cs42l42->suspended || !cs42l42->init_done) { + mutex_unlock(&cs42l42->irq_lock); + return IRQ_NONE; + } /* Read sticky registers to clear interurpt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { @@ -1611,7 +1669,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK); - /* Check auto-detect status */ + /* + * Check auto-detect status. Don't assume a previous unplug event has + * cleared the flags. If the jack is unplugged and plugged during + * system suspend there won't have been an unplug event. + */ if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); @@ -1619,11 +1681,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADSET, - SND_JACK_HEADSET); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; case CS42L42_PLUG_HEADPHONE: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADPHONE, - SND_JACK_HEADPHONE); + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); break; default: break; @@ -1647,18 +1713,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) cs42l42->plug_state = CS42L42_TS_UNPLUG; cs42l42_cancel_hs_type_detect(cs42l42); - switch (cs42l42->hs_type) { - case CS42L42_PLUG_CTIA: - case CS42L42_PLUG_OMTP: - snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADSET); - break; - case CS42L42_PLUG_HEADPHONE: - snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADPHONE); - break; - default: - break; - } snd_soc_jack_report(cs42l42->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); @@ -1667,8 +1723,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) break; default: - if (cs42l42->plug_state != CS42L42_TS_TRANS) - cs42l42->plug_state = CS42L42_TS_TRANS; + cs42l42->plug_state = CS42L42_TS_TRANS; } } @@ -1679,16 +1734,20 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) if (current_button_status & CS42L42_M_DETECT_TF_MASK) { dev_dbg(cs42l42->dev, "Button released\n"); - report = 0; + snd_soc_jack_report(cs42l42->jack, 0, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); } else if (current_button_status & CS42L42_M_DETECT_FT_MASK) { - report = cs42l42_handle_button_press(cs42l42); - + snd_soc_jack_report(cs42l42->jack, + cs42l42_handle_button_press(cs42l42), + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); } - snd_soc_jack_report(cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3); } } + mutex_unlock(&cs42l42->irq_lock); + return IRQ_HANDLED; } @@ -1801,6 +1860,13 @@ static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) cs42l42->hs_type = CS42L42_PLUG_INVALID; + /* + * DETECT_MODE must always be 0 with ADC and HP both off otherwise the + * FILT+ supply will not charge properly. + */ + regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK, 0); + /* Latch analog controls to VP power domain */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | @@ -2019,36 +2085,179 @@ static int cs42l42_handle_device_data(struct device *dev, return 0; } -static int cs42l42_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +/* Datasheet suspend sequence */ +static const struct reg_sequence __maybe_unused cs42l42_shutdown_seq[] = { + REG_SEQ0(CS42L42_MIC_DET_CTL1, 0x9F), + REG_SEQ0(CS42L42_ADC_OVFL_INT_MASK, 0x01), + REG_SEQ0(CS42L42_MIXER_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_SRC_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_ASP_RX_INT_MASK, 0x1F), + REG_SEQ0(CS42L42_ASP_TX_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_CODEC_INT_MASK, 0x03), + REG_SEQ0(CS42L42_SRCPL_INT_MASK, 0x7F), + REG_SEQ0(CS42L42_VPMON_INT_MASK, 0x01), + REG_SEQ0(CS42L42_PLL_LOCK_INT_MASK, 0x01), + REG_SEQ0(CS42L42_TSRS_PLUG_INT_MASK, 0x0F), + REG_SEQ0(CS42L42_WAKE_CTL, 0xE1), + REG_SEQ0(CS42L42_DET_INT1_MASK, 0xE0), + REG_SEQ0(CS42L42_DET_INT2_MASK, 0xFF), + REG_SEQ0(CS42L42_MIXER_CHA_VOL, 0x3F), + REG_SEQ0(CS42L42_MIXER_ADC_VOL, 0x3F), + REG_SEQ0(CS42L42_MIXER_CHB_VOL, 0x3F), + REG_SEQ0(CS42L42_HP_CTL, 0x0F), + REG_SEQ0(CS42L42_ASP_RX_DAI0_EN, 0x00), + REG_SEQ0(CS42L42_ASP_CLK_CFG, 0x00), + REG_SEQ0(CS42L42_HSDET_CTL2, 0x00), + REG_SEQ0(CS42L42_PWR_CTL1, 0xFE), + REG_SEQ0(CS42L42_PWR_CTL2, 0x8C), + REG_SEQ0(CS42L42_DAC_CTL2, 0x02), + REG_SEQ0(CS42L42_HS_CLAMP_DISABLE, 0x00), + REG_SEQ0(CS42L42_MISC_DET_CTL, 0x03), + REG_SEQ0(CS42L42_TIPSENSE_CTL, 0x02), + REG_SEQ0(CS42L42_HSBIAS_SC_AUTOCTL, 0x03), + REG_SEQ0(CS42L42_PWR_CTL1, 0xFF) +}; + +int cs42l42_suspend(struct device *dev) { - struct cs42l42_private *cs42l42; - int ret, i, devid; + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); unsigned int reg; + u8 save_regs[ARRAY_SIZE(cs42l42_shutdown_seq)]; + int i, ret; + + /* + * Wait for threaded irq handler to be idle and stop it processing + * future interrupts. This ensures a safe disable if the interrupt + * is shared. + */ + mutex_lock(&cs42l42->irq_lock); + cs42l42->suspended = true; - cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), - GFP_KERNEL); - if (!cs42l42) - return -ENOMEM; + /* Save register values that will be overwritten by shutdown sequence */ + for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { + regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); + save_regs[i] = (u8)reg; + } + + /* Shutdown codec */ + regmap_multi_reg_write(cs42l42->regmap, + cs42l42_shutdown_seq, + ARRAY_SIZE(cs42l42_shutdown_seq)); + + /* All interrupt sources are now disabled */ + mutex_unlock(&cs42l42->irq_lock); + + /* Wait for power-down complete */ + msleep(CS42L42_PDN_DONE_TIME_MS); + ret = regmap_read_poll_timeout(cs42l42->regmap, + CS42L42_CODEC_STATUS, reg, + (reg & CS42L42_PDN_DONE_MASK), + CS42L42_PDN_DONE_POLL_US, + CS42L42_PDN_DONE_TIMEOUT_US); + if (ret) + dev_warn(dev, "Failed to get PDN_DONE: %d\n", ret); - cs42l42->dev = &i2c_client->dev; - i2c_set_clientdata(i2c_client, cs42l42); + /* Discharge FILT+ */ + regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2, + CS42L42_DISCHARGE_FILT_MASK, CS42L42_DISCHARGE_FILT_MASK); + msleep(CS42L42_FILT_DISCHARGE_TIME_MS); - cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); - if (IS_ERR(cs42l42->regmap)) { - ret = PTR_ERR(cs42l42->regmap); - dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + regcache_cache_only(cs42l42->regmap, true); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); + + /* Restore register values to the regmap cache */ + for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) + regmap_write(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, save_regs[i]); + + /* The cached address page register value is now stale */ + regcache_drop_region(cs42l42->regmap, CS42L42_PAGE_REGISTER, CS42L42_PAGE_REGISTER); + + dev_dbg(dev, "System suspended\n"); + + return 0; + +} +EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE); + +int cs42l42_resume(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + int ret; + + /* + * If jack was unplugged and re-plugged during suspend it could + * have changed type but the tip-sense state hasn't changed. + * Force a plugged state to be re-evaluated. + */ + if (cs42l42->plug_state != CS42L42_TS_UNPLUG) + cs42l42->plug_state = CS42L42_TS_TRANS; + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret; } + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); + + dev_dbg(dev, "System resume powered up\n"); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE); + +void cs42l42_resume_restore(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + + regcache_cache_only(cs42l42->regmap, false); + regcache_mark_dirty(cs42l42->regmap); + + mutex_lock(&cs42l42->irq_lock); + /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ + regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); + regcache_sync(cs42l42->regmap); + + cs42l42->suspended = false; + mutex_unlock(&cs42l42->irq_lock); + + dev_dbg(dev, "System resumed\n"); +} +EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE); + +static int __maybe_unused cs42l42_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); + + return 0; +} + +int cs42l42_common_probe(struct cs42l42_private *cs42l42, + const struct snd_soc_component_driver *component_drv, + struct snd_soc_dai_driver *dai) +{ + int ret, i; + + dev_set_drvdata(cs42l42->dev, cs42l42); + mutex_init(&cs42l42->irq_lock); + + BUILD_BUG_ON(ARRAY_SIZE(cs42l42_supply_names) != ARRAY_SIZE(cs42l42->supplies)); for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) cs42l42->supplies[i].supply = cs42l42_supply_names[i]; - ret = devm_regulator_bulk_get(&i2c_client->dev, + ret = devm_regulator_bulk_get(cs42l42->dev, ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, + dev_err(cs42l42->dev, "Failed to request supplies: %d\n", ret); return ret; } @@ -2056,13 +2265,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, + dev_err(cs42l42->dev, "Failed to enable supplies: %d\n", ret); return ret; } /* Reset the Device */ - cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + cs42l42->reset_gpio = devm_gpiod_get_optional(cs42l42->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs42l42->reset_gpio)) { ret = PTR_ERR(cs42l42->reset_gpio); @@ -2070,50 +2279,74 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, } if (cs42l42->reset_gpio) { - dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + dev_dbg(cs42l42->dev, "Found reset GPIO\n"); gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); } usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); /* Request IRQ if one was specified */ - if (i2c_client->irq) { - ret = request_threaded_irq(i2c_client->irq, + if (cs42l42->irq) { + ret = request_threaded_irq(cs42l42->irq, NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); - if (ret == -EPROBE_DEFER) { - goto err_disable_noirq; - } else if (ret != 0) { - dev_err(&i2c_client->dev, - "Failed to request IRQ: %d\n", ret); + if (ret) { + dev_err_probe(cs42l42->dev, ret, + "Failed to request IRQ\n"); goto err_disable_noirq; } } + /* Register codec now so it can EPROBE_DEFER */ + ret = devm_snd_soc_register_component(cs42l42->dev, component_drv, dai, 1); + if (ret < 0) + goto err; + + return 0; + +err: + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); + +err_disable_noirq: + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); +err_disable_noreset: + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE); + +int cs42l42_init(struct cs42l42_private *cs42l42) +{ + unsigned int reg; + int devid, ret; + /* initialize codec */ devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB); if (devid < 0) { ret = devid; - dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + dev_err(cs42l42->dev, "Failed to read device ID: %d\n", ret); goto err_disable; } - if (devid != CS42L42_CHIP_ID) { + if (devid != cs42l42->devid) { ret = -ENODEV; - dev_err(&i2c_client->dev, - "CS42L42 Device ID (%X). Expected %X\n", - devid, CS42L42_CHIP_ID); + dev_err(cs42l42->dev, + "CS42L%x Device ID (%X). Expected %X\n", + cs42l42->devid & 0xff, devid, cs42l42->devid); goto err_disable; } ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); if (ret < 0) { - dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + dev_err(cs42l42->dev, "Get Revision ID failed\n"); goto err_shutdown; } - dev_info(&i2c_client->dev, - "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); + dev_info(cs42l42->dev, + "Cirrus Logic CS42L%x, Revision: %02X\n", + cs42l42->devid & 0xff, reg & 0xFF); /* Power up the codec */ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, @@ -2132,22 +2365,22 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, (1 << CS42L42_ADC_PDN_SHIFT) | (0 << CS42L42_PDN_ALL_SHIFT)); - ret = cs42l42_handle_device_data(&i2c_client->dev, cs42l42); + ret = cs42l42_handle_device_data(cs42l42->dev, cs42l42); if (ret != 0) goto err_shutdown; /* Setup headset detection */ cs42l42_setup_hs_type_detect(cs42l42); + /* + * Set init_done before unmasking interrupts so any triggered + * immediately will be handled. + */ + cs42l42->init_done = true; + /* Mask/Unmask Interrupts */ cs42l42_set_interrupt_masks(cs42l42); - /* Register codec for machine driver */ - ret = devm_snd_soc_register_component(&i2c_client->dev, - &soc_component_dev_cs42l42, &cs42l42_dai, 1); - if (ret < 0) - goto err_shutdown; - return 0; err_shutdown: @@ -2156,73 +2389,35 @@ err_shutdown: regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); err_disable: - if (i2c_client->irq) - free_irq(i2c_client->irq, cs42l42); + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); -err_disable_noirq: gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); -err_disable_noreset: regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); return ret; } +EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE); -static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +void cs42l42_common_remove(struct cs42l42_private *cs42l42) { - struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); - - if (i2c_client->irq) - free_irq(i2c_client->irq, cs42l42); + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); /* * The driver might not have control of reset and power supplies, * so ensure that the chip internals are powered down. */ - regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff); - regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff); - regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); + if (cs42l42->init_done) { + regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff); + regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff); + regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); + } gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); - - return 0; } - -#ifdef CONFIG_OF -static const struct of_device_id cs42l42_of_match[] = { - { .compatible = "cirrus,cs42l42", }, - {} -}; -MODULE_DEVICE_TABLE(of, cs42l42_of_match); -#endif - -#ifdef CONFIG_ACPI -static const struct acpi_device_id cs42l42_acpi_match[] = { - {"10134242", 0,}, - {} -}; -MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match); -#endif - -static const struct i2c_device_id cs42l42_id[] = { - {"cs42l42", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, cs42l42_id); - -static struct i2c_driver cs42l42_i2c_driver = { - .driver = { - .name = "cs42l42", - .of_match_table = of_match_ptr(cs42l42_of_match), - .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), - }, - .id_table = cs42l42_id, - .probe = cs42l42_i2c_probe, - .remove = cs42l42_i2c_remove, -}; - -module_i2c_driver(cs42l42_i2c_driver); +EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE); MODULE_DESCRIPTION("ASoC CS42L42 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index f45bcc9a3a62..a72136664112 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -2,7 +2,7 @@ /* * cs42l42.h -- CS42L42 ALSA SoC audio driver header * - * Copyright 2016 Cirrus Logic, Inc. + * Copyright 2016-2022 Cirrus Logic, Inc. * * Author: James Schulman <james.schulman@cirrus.com> * Author: Brian Austin <brian.austin@cirrus.com> @@ -12,824 +12,16 @@ #ifndef __CS42L42_H__ #define __CS42L42_H__ +#include <dt-bindings/sound/cs42l42.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <sound/jack.h> - -#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ -#define CS42L42_WIN_START 0x00 -#define CS42L42_WIN_LEN 0x100 -#define CS42L42_RANGE_MIN 0x00 -#define CS42L42_RANGE_MAX 0x7F - -#define CS42L42_PAGE_10 0x1000 -#define CS42L42_PAGE_11 0x1100 -#define CS42L42_PAGE_12 0x1200 -#define CS42L42_PAGE_13 0x1300 -#define CS42L42_PAGE_15 0x1500 -#define CS42L42_PAGE_19 0x1900 -#define CS42L42_PAGE_1B 0x1B00 -#define CS42L42_PAGE_1C 0x1C00 -#define CS42L42_PAGE_1D 0x1D00 -#define CS42L42_PAGE_1F 0x1F00 -#define CS42L42_PAGE_20 0x2000 -#define CS42L42_PAGE_21 0x2100 -#define CS42L42_PAGE_23 0x2300 -#define CS42L42_PAGE_24 0x2400 -#define CS42L42_PAGE_25 0x2500 -#define CS42L42_PAGE_26 0x2600 -#define CS42L42_PAGE_28 0x2800 -#define CS42L42_PAGE_29 0x2900 -#define CS42L42_PAGE_2A 0x2A00 -#define CS42L42_PAGE_30 0x3000 - -#define CS42L42_CHIP_ID 0x42A42 - -/* Page 0x10 Global Registers */ -#define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01) -#define CS42L42_DEVID_CD (CS42L42_PAGE_10 + 0x02) -#define CS42L42_DEVID_E (CS42L42_PAGE_10 + 0x03) -#define CS42L42_FABID (CS42L42_PAGE_10 + 0x04) -#define CS42L42_REVID (CS42L42_PAGE_10 + 0x05) -#define CS42L42_FRZ_CTL (CS42L42_PAGE_10 + 0x06) - -#define CS42L42_SRC_CTL (CS42L42_PAGE_10 + 0x07) -#define CS42L42_SRC_BYPASS_DAC_SHIFT 1 -#define CS42L42_SRC_BYPASS_DAC_MASK (1 << CS42L42_SRC_BYPASS_DAC_SHIFT) - -#define CS42L42_MCLK_STATUS (CS42L42_PAGE_10 + 0x08) - -#define CS42L42_MCLK_CTL (CS42L42_PAGE_10 + 0x09) -#define CS42L42_INTERNAL_FS_SHIFT 1 -#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT) - -#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A) -#define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E) -#define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F) -#define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10) - -/* Page 0x11 Power and Headset Detect Registers */ -#define CS42L42_PWR_CTL1 (CS42L42_PAGE_11 + 0x01) -#define CS42L42_ASP_DAO_PDN_SHIFT 7 -#define CS42L42_ASP_DAO_PDN_MASK (1 << CS42L42_ASP_DAO_PDN_SHIFT) -#define CS42L42_ASP_DAI_PDN_SHIFT 6 -#define CS42L42_ASP_DAI_PDN_MASK (1 << CS42L42_ASP_DAI_PDN_SHIFT) -#define CS42L42_MIXER_PDN_SHIFT 5 -#define CS42L42_MIXER_PDN_MASK (1 << CS42L42_MIXER_PDN_SHIFT) -#define CS42L42_EQ_PDN_SHIFT 4 -#define CS42L42_EQ_PDN_MASK (1 << CS42L42_EQ_PDN_SHIFT) -#define CS42L42_HP_PDN_SHIFT 3 -#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) -#define CS42L42_ADC_PDN_SHIFT 2 -#define CS42L42_ADC_PDN_MASK (1 << CS42L42_ADC_PDN_SHIFT) -#define CS42L42_PDN_ALL_SHIFT 0 -#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT) - -#define CS42L42_PWR_CTL2 (CS42L42_PAGE_11 + 0x02) -#define CS42L42_ADC_SRC_PDNB_SHIFT 0 -#define CS42L42_ADC_SRC_PDNB_MASK (1 << CS42L42_ADC_SRC_PDNB_SHIFT) -#define CS42L42_DAC_SRC_PDNB_SHIFT 1 -#define CS42L42_DAC_SRC_PDNB_MASK (1 << CS42L42_DAC_SRC_PDNB_SHIFT) -#define CS42L42_ASP_DAI1_PDN_SHIFT 2 -#define CS42L42_ASP_DAI1_PDN_MASK (1 << CS42L42_ASP_DAI1_PDN_SHIFT) -#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3 -#define CS42L42_SRC_PDN_OVERRIDE_MASK (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT) -#define CS42L42_DISCHARGE_FILT_SHIFT 4 -#define CS42L42_DISCHARGE_FILT_MASK (1 << CS42L42_DISCHARGE_FILT_SHIFT) - -#define CS42L42_PWR_CTL3 (CS42L42_PAGE_11 + 0x03) -#define CS42L42_RING_SENSE_PDNB_SHIFT 1 -#define CS42L42_RING_SENSE_PDNB_MASK (1 << \ - CS42L42_RING_SENSE_PDNB_SHIFT) -#define CS42L42_VPMON_PDNB_SHIFT 2 -#define CS42L42_VPMON_PDNB_MASK (1 << \ - CS42L42_VPMON_PDNB_SHIFT) -#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT 5 -#define CS42L42_SW_CLK_STP_STAT_SEL_MASK (3 << \ - CS42L42_SW_CLK_STP_STAT_SEL_SHIFT) - -#define CS42L42_RSENSE_CTL1 (CS42L42_PAGE_11 + 0x04) -#define CS42L42_RS_TRIM_R_SHIFT 0 -#define CS42L42_RS_TRIM_R_MASK (1 << \ - CS42L42_RS_TRIM_R_SHIFT) -#define CS42L42_RS_TRIM_T_SHIFT 1 -#define CS42L42_RS_TRIM_T_MASK (1 << \ - CS42L42_RS_TRIM_T_SHIFT) -#define CS42L42_HPREF_RS_SHIFT 2 -#define CS42L42_HPREF_RS_MASK (1 << \ - CS42L42_HPREF_RS_SHIFT) -#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT 3 -#define CS42L42_HSBIAS_FILT_REF_RS_MASK (1 << \ - CS42L42_HSBIAS_FILT_REF_RS_SHIFT) -#define CS42L42_RING_SENSE_PU_HIZ_SHIFT 6 -#define CS42L42_RING_SENSE_PU_HIZ_MASK (1 << \ - CS42L42_RING_SENSE_PU_HIZ_SHIFT) - -#define CS42L42_RSENSE_CTL2 (CS42L42_PAGE_11 + 0x05) -#define CS42L42_TS_RS_GATE_SHIFT 7 -#define CS42L42_TS_RS_GATE_MAS (1 << CS42L42_TS_RS_GATE_SHIFT) - -#define CS42L42_OSC_SWITCH (CS42L42_PAGE_11 + 0x07) -#define CS42L42_SCLK_PRESENT_SHIFT 0 -#define CS42L42_SCLK_PRESENT_MASK (1 << CS42L42_SCLK_PRESENT_SHIFT) - -#define CS42L42_OSC_SWITCH_STATUS (CS42L42_PAGE_11 + 0x09) -#define CS42L42_OSC_SW_SEL_STAT_SHIFT 0 -#define CS42L42_OSC_SW_SEL_STAT_MASK (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT) -#define CS42L42_OSC_PDNB_STAT_SHIFT 2 -#define CS42L42_OSC_PDNB_STAT_MASK (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT) - -#define CS42L42_RSENSE_CTL3 (CS42L42_PAGE_11 + 0x12) -#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT 0 -#define CS42L42_RS_RISE_DBNCE_TIME_MASK (7 << \ - CS42L42_RS_RISE_DBNCE_TIME_SHIFT) -#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT 3 -#define CS42L42_RS_FALL_DBNCE_TIME_MASK (7 << \ - CS42L42_RS_FALL_DBNCE_TIME_SHIFT) -#define CS42L42_RS_PU_EN_SHIFT 6 -#define CS42L42_RS_PU_EN_MASK (1 << \ - CS42L42_RS_PU_EN_SHIFT) -#define CS42L42_RS_INV_SHIFT 7 -#define CS42L42_RS_INV_MASK (1 << \ - CS42L42_RS_INV_SHIFT) - -#define CS42L42_TSENSE_CTL (CS42L42_PAGE_11 + 0x13) -#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT 0 -#define CS42L42_TS_RISE_DBNCE_TIME_MASK (7 << \ - CS42L42_TS_RISE_DBNCE_TIME_SHIFT) -#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT 3 -#define CS42L42_TS_FALL_DBNCE_TIME_MASK (7 << \ - CS42L42_TS_FALL_DBNCE_TIME_SHIFT) -#define CS42L42_TS_INV_SHIFT 7 -#define CS42L42_TS_INV_MASK (1 << \ - CS42L42_TS_INV_SHIFT) - -#define CS42L42_TSRS_INT_DISABLE (CS42L42_PAGE_11 + 0x14) -#define CS42L42_D_RS_PLUG_DBNC_SHIFT 0 -#define CS42L42_D_RS_PLUG_DBNC_MASK (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT) -#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1 -#define CS42L42_D_RS_UNPLUG_DBNC_MASK (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT) -#define CS42L42_D_TS_PLUG_DBNC_SHIFT 2 -#define CS42L42_D_TS_PLUG_DBNC_MASK (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT) -#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3 -#define CS42L42_D_TS_UNPLUG_DBNC_MASK (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT) - -#define CS42L42_TRSENSE_STATUS (CS42L42_PAGE_11 + 0x15) -#define CS42L42_RS_PLUG_DBNC_SHIFT 0 -#define CS42L42_RS_PLUG_DBNC_MASK (1 << CS42L42_RS_PLUG_DBNC_SHIFT) -#define CS42L42_RS_UNPLUG_DBNC_SHIFT 1 -#define CS42L42_RS_UNPLUG_DBNC_MASK (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT) -#define CS42L42_TS_PLUG_DBNC_SHIFT 2 -#define CS42L42_TS_PLUG_DBNC_MASK (1 << CS42L42_TS_PLUG_DBNC_SHIFT) -#define CS42L42_TS_UNPLUG_DBNC_SHIFT 3 -#define CS42L42_TS_UNPLUG_DBNC_MASK (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT) - -#define CS42L42_HSDET_CTL1 (CS42L42_PAGE_11 + 0x1F) -#define CS42L42_HSDET_COMP1_LVL_SHIFT 0 -#define CS42L42_HSDET_COMP1_LVL_MASK (15 << CS42L42_HSDET_COMP1_LVL_SHIFT) -#define CS42L42_HSDET_COMP2_LVL_SHIFT 4 -#define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT) - -#define CS42L42_HSDET_COMP1_LVL_VAL 12 /* 1.25V Comparator */ -#define CS42L42_HSDET_COMP2_LVL_VAL 2 /* 1.75V Comparator */ -#define CS42L42_HSDET_COMP1_LVL_DEFAULT 7 /* 1V Comparator */ -#define CS42L42_HSDET_COMP2_LVL_DEFAULT 7 /* 2V Comparator */ - -#define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20) -#define CS42L42_HSDET_AUTO_TIME_SHIFT 0 -#define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT) -#define CS42L42_HSBIAS_REF_SHIFT 3 -#define CS42L42_HSBIAS_REF_MASK (1 << CS42L42_HSBIAS_REF_SHIFT) -#define CS42L42_HSDET_SET_SHIFT 4 -#define CS42L42_HSDET_SET_MASK (3 << CS42L42_HSDET_SET_SHIFT) -#define CS42L42_HSDET_CTRL_SHIFT 6 -#define CS42L42_HSDET_CTRL_MASK (3 << CS42L42_HSDET_CTRL_SHIFT) - -#define CS42L42_HS_SWITCH_CTL (CS42L42_PAGE_11 + 0x21) -#define CS42L42_SW_GNDHS_HS4_SHIFT 0 -#define CS42L42_SW_GNDHS_HS4_MASK (1 << CS42L42_SW_GNDHS_HS4_SHIFT) -#define CS42L42_SW_GNDHS_HS3_SHIFT 1 -#define CS42L42_SW_GNDHS_HS3_MASK (1 << CS42L42_SW_GNDHS_HS3_SHIFT) -#define CS42L42_SW_HSB_HS4_SHIFT 2 -#define CS42L42_SW_HSB_HS4_MASK (1 << CS42L42_SW_HSB_HS4_SHIFT) -#define CS42L42_SW_HSB_HS3_SHIFT 3 -#define CS42L42_SW_HSB_HS3_MASK (1 << CS42L42_SW_HSB_HS3_SHIFT) -#define CS42L42_SW_HSB_FILT_HS4_SHIFT 4 -#define CS42L42_SW_HSB_FILT_HS4_MASK (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) -#define CS42L42_SW_HSB_FILT_HS3_SHIFT 5 -#define CS42L42_SW_HSB_FILT_HS3_MASK (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) -#define CS42L42_SW_REF_HS4_SHIFT 6 -#define CS42L42_SW_REF_HS4_MASK (1 << CS42L42_SW_REF_HS4_SHIFT) -#define CS42L42_SW_REF_HS3_SHIFT 7 -#define CS42L42_SW_REF_HS3_MASK (1 << CS42L42_SW_REF_HS3_SHIFT) - -#define CS42L42_HS_DET_STATUS (CS42L42_PAGE_11 + 0x24) -#define CS42L42_HSDET_TYPE_SHIFT 0 -#define CS42L42_HSDET_TYPE_MASK (3 << CS42L42_HSDET_TYPE_SHIFT) -#define CS42L42_HSDET_COMP1_OUT_SHIFT 6 -#define CS42L42_HSDET_COMP1_OUT_MASK (1 << CS42L42_HSDET_COMP1_OUT_SHIFT) -#define CS42L42_HSDET_COMP2_OUT_SHIFT 7 -#define CS42L42_HSDET_COMP2_OUT_MASK (1 << CS42L42_HSDET_COMP2_OUT_SHIFT) -#define CS42L42_PLUG_CTIA 0 -#define CS42L42_PLUG_OMTP 1 -#define CS42L42_PLUG_HEADPHONE 2 -#define CS42L42_PLUG_INVALID 3 - -#define CS42L42_HSDET_SW_COMP1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_COMP2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (0 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (0 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE3 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (1 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) -#define CS42L42_HSDET_SW_TYPE4 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ - (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ - (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ - (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ - (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ - (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ - (0 << CS42L42_SW_REF_HS4_SHIFT) | \ - (1 << CS42L42_SW_REF_HS3_SHIFT)) - -#define CS42L42_HSDET_COMP_TYPE1 1 -#define CS42L42_HSDET_COMP_TYPE2 2 -#define CS42L42_HSDET_COMP_TYPE3 0 -#define CS42L42_HSDET_COMP_TYPE4 3 - -#define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29) -#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0 -#define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) - -/* Page 0x12 Clocking Registers */ -#define CS42L42_MCLK_SRC_SEL (CS42L42_PAGE_12 + 0x01) -#define CS42L42_MCLKDIV_SHIFT 1 -#define CS42L42_MCLKDIV_MASK (1 << CS42L42_MCLKDIV_SHIFT) -#define CS42L42_MCLK_SRC_SEL_SHIFT 0 -#define CS42L42_MCLK_SRC_SEL_MASK (1 << CS42L42_MCLK_SRC_SEL_SHIFT) - -#define CS42L42_SPDIF_CLK_CFG (CS42L42_PAGE_12 + 0x02) -#define CS42L42_FSYNC_PW_LOWER (CS42L42_PAGE_12 + 0x03) - -#define CS42L42_FSYNC_PW_UPPER (CS42L42_PAGE_12 + 0x04) -#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT 0 -#define CS42L42_FSYNC_PULSE_WIDTH_MASK (0xff << \ - CS42L42_FSYNC_PULSE_WIDTH_SHIFT) - -#define CS42L42_FSYNC_P_LOWER (CS42L42_PAGE_12 + 0x05) - -#define CS42L42_FSYNC_P_UPPER (CS42L42_PAGE_12 + 0x06) -#define CS42L42_FSYNC_PERIOD_SHIFT 0 -#define CS42L42_FSYNC_PERIOD_MASK (0xff << CS42L42_FSYNC_PERIOD_SHIFT) - -#define CS42L42_ASP_CLK_CFG (CS42L42_PAGE_12 + 0x07) -#define CS42L42_ASP_SCLK_EN_SHIFT 5 -#define CS42L42_ASP_SCLK_EN_MASK (1 << CS42L42_ASP_SCLK_EN_SHIFT) -#define CS42L42_ASP_MASTER_MODE 0x01 -#define CS42L42_ASP_SLAVE_MODE 0x00 -#define CS42L42_ASP_MODE_SHIFT 4 -#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT) -#define CS42L42_ASP_SCPOL_SHIFT 2 -#define CS42L42_ASP_SCPOL_MASK (3 << CS42L42_ASP_SCPOL_SHIFT) -#define CS42L42_ASP_SCPOL_NOR 3 -#define CS42L42_ASP_LCPOL_SHIFT 0 -#define CS42L42_ASP_LCPOL_MASK (3 << CS42L42_ASP_LCPOL_SHIFT) -#define CS42L42_ASP_LCPOL_INV 3 - -#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08) -#define CS42L42_ASP_STP_SHIFT 4 -#define CS42L42_ASP_STP_MASK (1 << CS42L42_ASP_STP_SHIFT) -#define CS42L42_ASP_5050_SHIFT 3 -#define CS42L42_ASP_5050_MASK (1 << CS42L42_ASP_5050_SHIFT) -#define CS42L42_ASP_FSD_SHIFT 0 -#define CS42L42_ASP_FSD_MASK (7 << CS42L42_ASP_FSD_SHIFT) -#define CS42L42_ASP_FSD_0_5 1 -#define CS42L42_ASP_FSD_1_0 2 -#define CS42L42_ASP_FSD_1_5 3 -#define CS42L42_ASP_FSD_2_0 4 - -#define CS42L42_FS_RATE_EN (CS42L42_PAGE_12 + 0x09) -#define CS42L42_FS_EN_SHIFT 0 -#define CS42L42_FS_EN_MASK (0xf << CS42L42_FS_EN_SHIFT) -#define CS42L42_FS_EN_IASRC_96K 0x1 -#define CS42L42_FS_EN_OASRC_96K 0x2 - -#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A) -#define CS42L42_CLK_IASRC_SEL_SHIFT 0 -#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT) -#define CS42L42_CLK_IASRC_SEL_6 0 -#define CS42L42_CLK_IASRC_SEL_12 1 - -#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B) -#define CS42L42_CLK_OASRC_SEL_SHIFT 0 -#define CS42L42_CLK_OASRC_SEL_MASK (1 << CS42L42_CLK_OASRC_SEL_SHIFT) -#define CS42L42_CLK_OASRC_SEL_12 1 - -#define CS42L42_PLL_DIV_CFG1 (CS42L42_PAGE_12 + 0x0C) -#define CS42L42_SCLK_PREDIV_SHIFT 0 -#define CS42L42_SCLK_PREDIV_MASK (3 << CS42L42_SCLK_PREDIV_SHIFT) - -/* Page 0x13 Interrupt Registers */ -/* Interrupts */ -#define CS42L42_ADC_OVFL_STATUS (CS42L42_PAGE_13 + 0x01) -#define CS42L42_MIXER_STATUS (CS42L42_PAGE_13 + 0x02) -#define CS42L42_SRC_STATUS (CS42L42_PAGE_13 + 0x03) -#define CS42L42_ASP_RX_STATUS (CS42L42_PAGE_13 + 0x04) -#define CS42L42_ASP_TX_STATUS (CS42L42_PAGE_13 + 0x05) -#define CS42L42_CODEC_STATUS (CS42L42_PAGE_13 + 0x08) -#define CS42L42_DET_INT_STATUS1 (CS42L42_PAGE_13 + 0x09) -#define CS42L42_DET_INT_STATUS2 (CS42L42_PAGE_13 + 0x0A) -#define CS42L42_SRCPL_INT_STATUS (CS42L42_PAGE_13 + 0x0B) -#define CS42L42_VPMON_STATUS (CS42L42_PAGE_13 + 0x0D) -#define CS42L42_PLL_LOCK_STATUS (CS42L42_PAGE_13 + 0x0E) -#define CS42L42_TSRS_PLUG_STATUS (CS42L42_PAGE_13 + 0x0F) -/* Masks */ -#define CS42L42_ADC_OVFL_INT_MASK (CS42L42_PAGE_13 + 0x16) -#define CS42L42_ADC_OVFL_SHIFT 0 -#define CS42L42_ADC_OVFL_MASK (1 << CS42L42_ADC_OVFL_SHIFT) -#define CS42L42_ADC_OVFL_VAL_MASK CS42L42_ADC_OVFL_MASK - -#define CS42L42_MIXER_INT_MASK (CS42L42_PAGE_13 + 0x17) -#define CS42L42_MIX_CHB_OVFL_SHIFT 0 -#define CS42L42_MIX_CHB_OVFL_MASK (1 << CS42L42_MIX_CHB_OVFL_SHIFT) -#define CS42L42_MIX_CHA_OVFL_SHIFT 1 -#define CS42L42_MIX_CHA_OVFL_MASK (1 << CS42L42_MIX_CHA_OVFL_SHIFT) -#define CS42L42_EQ_OVFL_SHIFT 2 -#define CS42L42_EQ_OVFL_MASK (1 << CS42L42_EQ_OVFL_SHIFT) -#define CS42L42_EQ_BIQUAD_OVFL_SHIFT 3 -#define CS42L42_EQ_BIQUAD_OVFL_MASK (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT) -#define CS42L42_MIXER_VAL_MASK (CS42L42_MIX_CHB_OVFL_MASK | \ - CS42L42_MIX_CHA_OVFL_MASK | \ - CS42L42_EQ_OVFL_MASK | \ - CS42L42_EQ_BIQUAD_OVFL_MASK) - -#define CS42L42_SRC_INT_MASK (CS42L42_PAGE_13 + 0x18) -#define CS42L42_SRC_ILK_SHIFT 0 -#define CS42L42_SRC_ILK_MASK (1 << CS42L42_SRC_ILK_SHIFT) -#define CS42L42_SRC_OLK_SHIFT 1 -#define CS42L42_SRC_OLK_MASK (1 << CS42L42_SRC_OLK_SHIFT) -#define CS42L42_SRC_IUNLK_SHIFT 2 -#define CS42L42_SRC_IUNLK_MASK (1 << CS42L42_SRC_IUNLK_SHIFT) -#define CS42L42_SRC_OUNLK_SHIFT 3 -#define CS42L42_SRC_OUNLK_MASK (1 << CS42L42_SRC_OUNLK_SHIFT) -#define CS42L42_SRC_VAL_MASK (CS42L42_SRC_ILK_MASK | \ - CS42L42_SRC_OLK_MASK | \ - CS42L42_SRC_IUNLK_MASK | \ - CS42L42_SRC_OUNLK_MASK) - -#define CS42L42_ASP_RX_INT_MASK (CS42L42_PAGE_13 + 0x19) -#define CS42L42_ASPRX_NOLRCK_SHIFT 0 -#define CS42L42_ASPRX_NOLRCK_MASK (1 << CS42L42_ASPRX_NOLRCK_SHIFT) -#define CS42L42_ASPRX_EARLY_SHIFT 1 -#define CS42L42_ASPRX_EARLY_MASK (1 << CS42L42_ASPRX_EARLY_SHIFT) -#define CS42L42_ASPRX_LATE_SHIFT 2 -#define CS42L42_ASPRX_LATE_MASK (1 << CS42L42_ASPRX_LATE_SHIFT) -#define CS42L42_ASPRX_ERROR_SHIFT 3 -#define CS42L42_ASPRX_ERROR_MASK (1 << CS42L42_ASPRX_ERROR_SHIFT) -#define CS42L42_ASPRX_OVLD_SHIFT 4 -#define CS42L42_ASPRX_OVLD_MASK (1 << CS42L42_ASPRX_OVLD_SHIFT) -#define CS42L42_ASP_RX_VAL_MASK (CS42L42_ASPRX_NOLRCK_MASK | \ - CS42L42_ASPRX_EARLY_MASK | \ - CS42L42_ASPRX_LATE_MASK | \ - CS42L42_ASPRX_ERROR_MASK | \ - CS42L42_ASPRX_OVLD_MASK) - -#define CS42L42_ASP_TX_INT_MASK (CS42L42_PAGE_13 + 0x1A) -#define CS42L42_ASPTX_NOLRCK_SHIFT 0 -#define CS42L42_ASPTX_NOLRCK_MASK (1 << CS42L42_ASPTX_NOLRCK_SHIFT) -#define CS42L42_ASPTX_EARLY_SHIFT 1 -#define CS42L42_ASPTX_EARLY_MASK (1 << CS42L42_ASPTX_EARLY_SHIFT) -#define CS42L42_ASPTX_LATE_SHIFT 2 -#define CS42L42_ASPTX_LATE_MASK (1 << CS42L42_ASPTX_LATE_SHIFT) -#define CS42L42_ASPTX_SMERROR_SHIFT 3 -#define CS42L42_ASPTX_SMERROR_MASK (1 << CS42L42_ASPTX_SMERROR_SHIFT) -#define CS42L42_ASP_TX_VAL_MASK (CS42L42_ASPTX_NOLRCK_MASK | \ - CS42L42_ASPTX_EARLY_MASK | \ - CS42L42_ASPTX_LATE_MASK | \ - CS42L42_ASPTX_SMERROR_MASK) - -#define CS42L42_CODEC_INT_MASK (CS42L42_PAGE_13 + 0x1B) -#define CS42L42_PDN_DONE_SHIFT 0 -#define CS42L42_PDN_DONE_MASK (1 << CS42L42_PDN_DONE_SHIFT) -#define CS42L42_HSDET_AUTO_DONE_SHIFT 1 -#define CS42L42_HSDET_AUTO_DONE_MASK (1 << CS42L42_HSDET_AUTO_DONE_SHIFT) -#define CS42L42_CODEC_VAL_MASK (CS42L42_PDN_DONE_MASK | \ - CS42L42_HSDET_AUTO_DONE_MASK) - -#define CS42L42_SRCPL_INT_MASK (CS42L42_PAGE_13 + 0x1C) -#define CS42L42_SRCPL_ADC_LK_SHIFT 0 -#define CS42L42_SRCPL_ADC_LK_MASK (1 << CS42L42_SRCPL_ADC_LK_SHIFT) -#define CS42L42_SRCPL_DAC_LK_SHIFT 2 -#define CS42L42_SRCPL_DAC_LK_MASK (1 << CS42L42_SRCPL_DAC_LK_SHIFT) -#define CS42L42_SRCPL_ADC_UNLK_SHIFT 5 -#define CS42L42_SRCPL_ADC_UNLK_MASK (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) -#define CS42L42_SRCPL_DAC_UNLK_SHIFT 6 -#define CS42L42_SRCPL_DAC_UNLK_MASK (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT) -#define CS42L42_SRCPL_VAL_MASK (CS42L42_SRCPL_ADC_LK_MASK | \ - CS42L42_SRCPL_DAC_LK_MASK | \ - CS42L42_SRCPL_ADC_UNLK_MASK | \ - CS42L42_SRCPL_DAC_UNLK_MASK) - -#define CS42L42_VPMON_INT_MASK (CS42L42_PAGE_13 + 0x1E) -#define CS42L42_VPMON_SHIFT 0 -#define CS42L42_VPMON_MASK (1 << CS42L42_VPMON_SHIFT) -#define CS42L42_VPMON_VAL_MASK CS42L42_VPMON_MASK - -#define CS42L42_PLL_LOCK_INT_MASK (CS42L42_PAGE_13 + 0x1F) -#define CS42L42_PLL_LOCK_SHIFT 0 -#define CS42L42_PLL_LOCK_MASK (1 << CS42L42_PLL_LOCK_SHIFT) -#define CS42L42_PLL_LOCK_VAL_MASK CS42L42_PLL_LOCK_MASK - -#define CS42L42_TSRS_PLUG_INT_MASK (CS42L42_PAGE_13 + 0x20) -#define CS42L42_RS_PLUG_SHIFT 0 -#define CS42L42_RS_PLUG_MASK (1 << CS42L42_RS_PLUG_SHIFT) -#define CS42L42_RS_UNPLUG_SHIFT 1 -#define CS42L42_RS_UNPLUG_MASK (1 << CS42L42_RS_UNPLUG_SHIFT) -#define CS42L42_TS_PLUG_SHIFT 2 -#define CS42L42_TS_PLUG_MASK (1 << CS42L42_TS_PLUG_SHIFT) -#define CS42L42_TS_UNPLUG_SHIFT 3 -#define CS42L42_TS_UNPLUG_MASK (1 << CS42L42_TS_UNPLUG_SHIFT) -#define CS42L42_TSRS_PLUG_VAL_MASK (CS42L42_RS_PLUG_MASK | \ - CS42L42_RS_UNPLUG_MASK | \ - CS42L42_TS_PLUG_MASK | \ - CS42L42_TS_UNPLUG_MASK) -#define CS42L42_TS_PLUG 3 -#define CS42L42_TS_UNPLUG 0 -#define CS42L42_TS_TRANS 1 - -/* Page 0x15 Fractional-N PLL Registers */ -#define CS42L42_PLL_CTL1 (CS42L42_PAGE_15 + 0x01) -#define CS42L42_PLL_START_SHIFT 0 -#define CS42L42_PLL_START_MASK (1 << CS42L42_PLL_START_SHIFT) - -#define CS42L42_PLL_DIV_FRAC0 (CS42L42_PAGE_15 + 0x02) -#define CS42L42_PLL_DIV_FRAC_SHIFT 0 -#define CS42L42_PLL_DIV_FRAC_MASK (0xff << CS42L42_PLL_DIV_FRAC_SHIFT) - -#define CS42L42_PLL_DIV_FRAC1 (CS42L42_PAGE_15 + 0x03) -#define CS42L42_PLL_DIV_FRAC2 (CS42L42_PAGE_15 + 0x04) - -#define CS42L42_PLL_DIV_INT (CS42L42_PAGE_15 + 0x05) -#define CS42L42_PLL_DIV_INT_SHIFT 0 -#define CS42L42_PLL_DIV_INT_MASK (0xff << CS42L42_PLL_DIV_INT_SHIFT) - -#define CS42L42_PLL_CTL3 (CS42L42_PAGE_15 + 0x08) -#define CS42L42_PLL_DIVOUT_SHIFT 0 -#define CS42L42_PLL_DIVOUT_MASK (0xff << CS42L42_PLL_DIVOUT_SHIFT) - -#define CS42L42_PLL_CAL_RATIO (CS42L42_PAGE_15 + 0x0A) -#define CS42L42_PLL_CAL_RATIO_SHIFT 0 -#define CS42L42_PLL_CAL_RATIO_MASK (0xff << CS42L42_PLL_CAL_RATIO_SHIFT) - -#define CS42L42_PLL_CTL4 (CS42L42_PAGE_15 + 0x1B) -#define CS42L42_PLL_MODE_SHIFT 0 -#define CS42L42_PLL_MODE_MASK (3 << CS42L42_PLL_MODE_SHIFT) - -/* Page 0x19 HP Load Detect Registers */ -#define CS42L42_LOAD_DET_RCSTAT (CS42L42_PAGE_19 + 0x25) -#define CS42L42_RLA_STAT_SHIFT 0 -#define CS42L42_RLA_STAT_MASK (3 << CS42L42_RLA_STAT_SHIFT) -#define CS42L42_RLA_STAT_15_OHM 0 - -#define CS42L42_LOAD_DET_DONE (CS42L42_PAGE_19 + 0x26) -#define CS42L42_HPLOAD_DET_DONE_SHIFT 0 -#define CS42L42_HPLOAD_DET_DONE_MASK (1 << CS42L42_HPLOAD_DET_DONE_SHIFT) - -#define CS42L42_LOAD_DET_EN (CS42L42_PAGE_19 + 0x27) -#define CS42L42_HP_LD_EN_SHIFT 0 -#define CS42L42_HP_LD_EN_MASK (1 << CS42L42_HP_LD_EN_SHIFT) - -/* Page 0x1B Headset Interface Registers */ -#define CS42L42_HSBIAS_SC_AUTOCTL (CS42L42_PAGE_1B + 0x70) -#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT 0 -#define CS42L42_HSBIAS_SENSE_TRIP_MASK (7 << \ - CS42L42_HSBIAS_SENSE_TRIP_SHIFT) -#define CS42L42_TIP_SENSE_EN_SHIFT 5 -#define CS42L42_TIP_SENSE_EN_MASK (1 << \ - CS42L42_TIP_SENSE_EN_SHIFT) -#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT 6 -#define CS42L42_AUTO_HSBIAS_HIZ_MASK (1 << \ - CS42L42_AUTO_HSBIAS_HIZ_SHIFT) -#define CS42L42_HSBIAS_SENSE_EN_SHIFT 7 -#define CS42L42_HSBIAS_SENSE_EN_MASK (1 << \ - CS42L42_HSBIAS_SENSE_EN_SHIFT) - -#define CS42L42_WAKE_CTL (CS42L42_PAGE_1B + 0x71) -#define CS42L42_WAKEB_CLEAR_SHIFT 0 -#define CS42L42_WAKEB_CLEAR_MASK (1 << CS42L42_WAKEB_CLEAR_SHIFT) -#define CS42L42_WAKEB_MODE_SHIFT 5 -#define CS42L42_WAKEB_MODE_MASK (1 << CS42L42_WAKEB_MODE_SHIFT) -#define CS42L42_M_HP_WAKE_SHIFT 6 -#define CS42L42_M_HP_WAKE_MASK (1 << CS42L42_M_HP_WAKE_SHIFT) -#define CS42L42_M_MIC_WAKE_SHIFT 7 -#define CS42L42_M_MIC_WAKE_MASK (1 << CS42L42_M_MIC_WAKE_SHIFT) - -#define CS42L42_ADC_DISABLE_MUTE (CS42L42_PAGE_1B + 0x72) -#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT 7 -#define CS42L42_ADC_DISABLE_S0_MUTE_MASK (1 << \ - CS42L42_ADC_DISABLE_S0_MUTE_SHIFT) - -#define CS42L42_TIPSENSE_CTL (CS42L42_PAGE_1B + 0x73) -#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT 0 -#define CS42L42_TIP_SENSE_DEBOUNCE_MASK (3 << \ - CS42L42_TIP_SENSE_DEBOUNCE_SHIFT) -#define CS42L42_TIP_SENSE_INV_SHIFT 5 -#define CS42L42_TIP_SENSE_INV_MASK (1 << \ - CS42L42_TIP_SENSE_INV_SHIFT) -#define CS42L42_TIP_SENSE_CTRL_SHIFT 6 -#define CS42L42_TIP_SENSE_CTRL_MASK (3 << \ - CS42L42_TIP_SENSE_CTRL_SHIFT) - -#define CS42L42_MISC_DET_CTL (CS42L42_PAGE_1B + 0x74) -#define CS42L42_PDN_MIC_LVL_DET_SHIFT 0 -#define CS42L42_PDN_MIC_LVL_DET_MASK (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT) -#define CS42L42_HSBIAS_CTL_SHIFT 1 -#define CS42L42_HSBIAS_CTL_MASK (3 << CS42L42_HSBIAS_CTL_SHIFT) -#define CS42L42_DETECT_MODE_SHIFT 3 -#define CS42L42_DETECT_MODE_MASK (3 << CS42L42_DETECT_MODE_SHIFT) - -#define CS42L42_MIC_DET_CTL1 (CS42L42_PAGE_1B + 0x75) -#define CS42L42_HS_DET_LEVEL_SHIFT 0 -#define CS42L42_HS_DET_LEVEL_MASK (0x3F << CS42L42_HS_DET_LEVEL_SHIFT) -#define CS42L42_EVENT_STAT_SEL_SHIFT 6 -#define CS42L42_EVENT_STAT_SEL_MASK (1 << CS42L42_EVENT_STAT_SEL_SHIFT) -#define CS42L42_LATCH_TO_VP_SHIFT 7 -#define CS42L42_LATCH_TO_VP_MASK (1 << CS42L42_LATCH_TO_VP_SHIFT) - -#define CS42L42_MIC_DET_CTL2 (CS42L42_PAGE_1B + 0x76) -#define CS42L42_DEBOUNCE_TIME_SHIFT 5 -#define CS42L42_DEBOUNCE_TIME_MASK (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT) - -#define CS42L42_DET_STATUS1 (CS42L42_PAGE_1B + 0x77) -#define CS42L42_HSBIAS_HIZ_MODE_SHIFT 6 -#define CS42L42_HSBIAS_HIZ_MODE_MASK (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT) -#define CS42L42_TIP_SENSE_SHIFT 7 -#define CS42L42_TIP_SENSE_MASK (1 << CS42L42_TIP_SENSE_SHIFT) - -#define CS42L42_DET_STATUS2 (CS42L42_PAGE_1B + 0x78) -#define CS42L42_SHORT_TRUE_SHIFT 0 -#define CS42L42_SHORT_TRUE_MASK (1 << CS42L42_SHORT_TRUE_SHIFT) -#define CS42L42_HS_TRUE_SHIFT 1 -#define CS42L42_HS_TRUE_MASK (1 << CS42L42_HS_TRUE_SHIFT) - -#define CS42L42_DET_INT1_MASK (CS42L42_PAGE_1B + 0x79) -#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5 -#define CS42L42_TIP_SENSE_UNPLUG_MASK (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) -#define CS42L42_TIP_SENSE_PLUG_SHIFT 6 -#define CS42L42_TIP_SENSE_PLUG_MASK (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) -#define CS42L42_HSBIAS_SENSE_SHIFT 7 -#define CS42L42_HSBIAS_SENSE_MASK (1 << CS42L42_HSBIAS_SENSE_SHIFT) -#define CS42L42_DET_INT_VAL1_MASK (CS42L42_TIP_SENSE_UNPLUG_MASK | \ - CS42L42_TIP_SENSE_PLUG_MASK | \ - CS42L42_HSBIAS_SENSE_MASK) - -#define CS42L42_DET_INT2_MASK (CS42L42_PAGE_1B + 0x7A) -#define CS42L42_M_SHORT_DET_SHIFT 0 -#define CS42L42_M_SHORT_DET_MASK (1 << \ - CS42L42_M_SHORT_DET_SHIFT) -#define CS42L42_M_SHORT_RLS_SHIFT 1 -#define CS42L42_M_SHORT_RLS_MASK (1 << \ - CS42L42_M_SHORT_RLS_SHIFT) -#define CS42L42_M_HSBIAS_HIZ_SHIFT 2 -#define CS42L42_M_HSBIAS_HIZ_MASK (1 << \ - CS42L42_M_HSBIAS_HIZ_SHIFT) -#define CS42L42_M_DETECT_FT_SHIFT 6 -#define CS42L42_M_DETECT_FT_MASK (1 << \ - CS42L42_M_DETECT_FT_SHIFT) -#define CS42L42_M_DETECT_TF_SHIFT 7 -#define CS42L42_M_DETECT_TF_MASK (1 << \ - CS42L42_M_DETECT_TF_SHIFT) -#define CS42L42_DET_INT_VAL2_MASK (CS42L42_M_SHORT_DET_MASK | \ - CS42L42_M_SHORT_RLS_MASK | \ - CS42L42_M_HSBIAS_HIZ_MASK | \ - CS42L42_M_DETECT_FT_MASK | \ - CS42L42_M_DETECT_TF_MASK) - -/* Page 0x1C Headset Bias Registers */ -#define CS42L42_HS_BIAS_CTL (CS42L42_PAGE_1C + 0x03) -#define CS42L42_HSBIAS_RAMP_SHIFT 0 -#define CS42L42_HSBIAS_RAMP_MASK (3 << CS42L42_HSBIAS_RAMP_SHIFT) -#define CS42L42_HSBIAS_PD_SHIFT 4 -#define CS42L42_HSBIAS_PD_MASK (1 << CS42L42_HSBIAS_PD_SHIFT) -#define CS42L42_HSBIAS_CAPLESS_SHIFT 7 -#define CS42L42_HSBIAS_CAPLESS_MASK (1 << CS42L42_HSBIAS_CAPLESS_SHIFT) - -/* Page 0x1D ADC Registers */ -#define CS42L42_ADC_CTL (CS42L42_PAGE_1D + 0x01) -#define CS42L42_ADC_NOTCH_DIS_SHIFT 5 -#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT 4 -#define CS42L42_ADC_INV_SHIFT 2 -#define CS42L42_ADC_DIG_BOOST_SHIFT 0 - -#define CS42L42_ADC_VOLUME (CS42L42_PAGE_1D + 0x03) -#define CS42L42_ADC_VOL_SHIFT 0 - -#define CS42L42_ADC_WNF_HPF_CTL (CS42L42_PAGE_1D + 0x04) -#define CS42L42_ADC_WNF_CF_SHIFT 4 -#define CS42L42_ADC_WNF_EN_SHIFT 3 -#define CS42L42_ADC_HPF_CF_SHIFT 1 -#define CS42L42_ADC_HPF_EN_SHIFT 0 - -/* Page 0x1F DAC Registers */ -#define CS42L42_DAC_CTL1 (CS42L42_PAGE_1F + 0x01) -#define CS42L42_DACB_INV_SHIFT 1 -#define CS42L42_DACA_INV_SHIFT 0 - -#define CS42L42_DAC_CTL2 (CS42L42_PAGE_1F + 0x06) -#define CS42L42_HPOUT_PULLDOWN_SHIFT 4 -#define CS42L42_HPOUT_PULLDOWN_MASK (15 << CS42L42_HPOUT_PULLDOWN_SHIFT) -#define CS42L42_HPOUT_LOAD_SHIFT 3 -#define CS42L42_HPOUT_LOAD_MASK (1 << CS42L42_HPOUT_LOAD_SHIFT) -#define CS42L42_HPOUT_CLAMP_SHIFT 2 -#define CS42L42_HPOUT_CLAMP_MASK (1 << CS42L42_HPOUT_CLAMP_SHIFT) -#define CS42L42_DAC_HPF_EN_SHIFT 1 -#define CS42L42_DAC_HPF_EN_MASK (1 << CS42L42_DAC_HPF_EN_SHIFT) -#define CS42L42_DAC_MON_EN_SHIFT 0 -#define CS42L42_DAC_MON_EN_MASK (1 << CS42L42_DAC_MON_EN_SHIFT) - -/* Page 0x20 HP CTL Registers */ -#define CS42L42_HP_CTL (CS42L42_PAGE_20 + 0x01) -#define CS42L42_HP_ANA_BMUTE_SHIFT 3 -#define CS42L42_HP_ANA_BMUTE_MASK (1 << CS42L42_HP_ANA_BMUTE_SHIFT) -#define CS42L42_HP_ANA_AMUTE_SHIFT 2 -#define CS42L42_HP_ANA_AMUTE_MASK (1 << CS42L42_HP_ANA_AMUTE_SHIFT) -#define CS42L42_HP_FULL_SCALE_VOL_SHIFT 1 -#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT) - -/* Page 0x21 Class H Registers */ -#define CS42L42_CLASSH_CTL (CS42L42_PAGE_21 + 0x01) - -/* Page 0x23 Mixer Volume Registers */ -#define CS42L42_MIXER_CHA_VOL (CS42L42_PAGE_23 + 0x01) -#define CS42L42_MIXER_ADC_VOL (CS42L42_PAGE_23 + 0x02) - -#define CS42L42_MIXER_CHB_VOL (CS42L42_PAGE_23 + 0x03) -#define CS42L42_MIXER_CH_VOL_SHIFT 0 -#define CS42L42_MIXER_CH_VOL_MASK (0x3f << CS42L42_MIXER_CH_VOL_SHIFT) - -/* Page 0x24 EQ Registers */ -#define CS42L42_EQ_COEF_IN0 (CS42L42_PAGE_24 + 0x01) -#define CS42L42_EQ_COEF_IN1 (CS42L42_PAGE_24 + 0x02) -#define CS42L42_EQ_COEF_IN2 (CS42L42_PAGE_24 + 0x03) -#define CS42L42_EQ_COEF_IN3 (CS42L42_PAGE_24 + 0x04) -#define CS42L42_EQ_COEF_RW (CS42L42_PAGE_24 + 0x06) -#define CS42L42_EQ_COEF_OUT0 (CS42L42_PAGE_24 + 0x07) -#define CS42L42_EQ_COEF_OUT1 (CS42L42_PAGE_24 + 0x08) -#define CS42L42_EQ_COEF_OUT2 (CS42L42_PAGE_24 + 0x09) -#define CS42L42_EQ_COEF_OUT3 (CS42L42_PAGE_24 + 0x0A) -#define CS42L42_EQ_INIT_STAT (CS42L42_PAGE_24 + 0x0B) -#define CS42L42_EQ_START_FILT (CS42L42_PAGE_24 + 0x0C) -#define CS42L42_EQ_MUTE_CTL (CS42L42_PAGE_24 + 0x0E) - -/* Page 0x25 Audio Port Registers */ -#define CS42L42_SP_RX_CH_SEL (CS42L42_PAGE_25 + 0x01) -#define CS42L42_SP_RX_CHB_SEL_SHIFT 2 -#define CS42L42_SP_RX_CHB_SEL_MASK (3 << CS42L42_SP_RX_CHB_SEL_SHIFT) - -#define CS42L42_SP_RX_ISOC_CTL (CS42L42_PAGE_25 + 0x02) -#define CS42L42_SP_RX_RSYNC_SHIFT 6 -#define CS42L42_SP_RX_RSYNC_MASK (1 << CS42L42_SP_RX_RSYNC_SHIFT) -#define CS42L42_SP_RX_NSB_POS_SHIFT 3 -#define CS42L42_SP_RX_NSB_POS_MASK (7 << CS42L42_SP_RX_NSB_POS_SHIFT) -#define CS42L42_SP_RX_NFS_NSBB_SHIFT 2 -#define CS42L42_SP_RX_NFS_NSBB_MASK (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT) -#define CS42L42_SP_RX_ISOC_MODE_SHIFT 0 -#define CS42L42_SP_RX_ISOC_MODE_MASK (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT) - -#define CS42L42_SP_RX_FS (CS42L42_PAGE_25 + 0x03) -#define CS42l42_SPDIF_CH_SEL (CS42L42_PAGE_25 + 0x04) -#define CS42L42_SP_TX_ISOC_CTL (CS42L42_PAGE_25 + 0x05) -#define CS42L42_SP_TX_FS (CS42L42_PAGE_25 + 0x06) -#define CS42L42_SPDIF_SW_CTL1 (CS42L42_PAGE_25 + 0x07) - -/* Page 0x26 SRC Registers */ -#define CS42L42_SRC_SDIN_FS (CS42L42_PAGE_26 + 0x01) -#define CS42L42_SRC_SDIN_FS_SHIFT 0 -#define CS42L42_SRC_SDIN_FS_MASK (0x1f << CS42L42_SRC_SDIN_FS_SHIFT) - -#define CS42L42_SRC_SDOUT_FS (CS42L42_PAGE_26 + 0x09) - -/* Page 0x28 S/PDIF Registers */ -#define CS42L42_SPDIF_CTL1 (CS42L42_PAGE_28 + 0x01) -#define CS42L42_SPDIF_CTL2 (CS42L42_PAGE_28 + 0x02) -#define CS42L42_SPDIF_CTL3 (CS42L42_PAGE_28 + 0x03) -#define CS42L42_SPDIF_CTL4 (CS42L42_PAGE_28 + 0x04) - -/* Page 0x29 Serial Port TX Registers */ -#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01) -#define CS42L42_ASP_TX_EN_SHIFT 0 -#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02) -#define CS42L42_ASP_TX0_CH2_SHIFT 1 -#define CS42L42_ASP_TX0_CH1_SHIFT 0 - -#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03) -#define CS42L42_ASP_TX_CH1_AP_SHIFT 7 -#define CS42L42_ASP_TX_CH1_AP_MASK (1 << CS42L42_ASP_TX_CH1_AP_SHIFT) -#define CS42L42_ASP_TX_CH2_AP_SHIFT 6 -#define CS42L42_ASP_TX_CH2_AP_MASK (1 << CS42L42_ASP_TX_CH2_AP_SHIFT) -#define CS42L42_ASP_TX_CH2_RES_SHIFT 2 -#define CS42L42_ASP_TX_CH2_RES_MASK (3 << CS42L42_ASP_TX_CH2_RES_SHIFT) -#define CS42L42_ASP_TX_CH1_RES_SHIFT 0 -#define CS42L42_ASP_TX_CH1_RES_MASK (3 << CS42L42_ASP_TX_CH1_RES_SHIFT) -#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04) -#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05) -#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06) -#define CS42L42_ASP_TX_CH2_BIT_MSB (CS42L42_PAGE_29 + 0x0A) -#define CS42L42_ASP_TX_CH2_BIT_LSB (CS42L42_PAGE_29 + 0x0B) - -/* Page 0x2A Serial Port RX Registers */ -#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01) -#define CS42L42_ASP_RX0_CH_EN_SHIFT 2 -#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) -#define CS42L42_ASP_RX0_CH1_SHIFT 2 -#define CS42L42_ASP_RX0_CH2_SHIFT 3 -#define CS42L42_ASP_RX0_CH3_SHIFT 4 -#define CS42L42_ASP_RX0_CH4_SHIFT 5 - -#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02) -#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03) -#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x04) -#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05) -#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x06) -#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x07) -#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08) -#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB (CS42L42_PAGE_2A + 0x09) -#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB (CS42L42_PAGE_2A + 0x0A) -#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B) -#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB (CS42L42_PAGE_2A + 0x0C) -#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB (CS42L42_PAGE_2A + 0x0D) -#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E) -#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x0F) -#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x10) -#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11) -#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x12) -#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x13) - -#define CS42L42_ASP_RX_CH_AP_SHIFT 6 -#define CS42L42_ASP_RX_CH_AP_MASK (1 << CS42L42_ASP_RX_CH_AP_SHIFT) -#define CS42L42_ASP_RX_CH_AP_LOW 0 -#define CS42L42_ASP_RX_CH_AP_HI 1 -#define CS42L42_ASP_RX_CH_RES_SHIFT 0 -#define CS42L42_ASP_RX_CH_RES_MASK (3 << CS42L42_ASP_RX_CH_RES_SHIFT) -#define CS42L42_ASP_RX_CH_RES_32 3 -#define CS42L42_ASP_RX_CH_RES_16 1 -#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0 -#define CS42L42_ASP_RX_CH_BIT_ST_MASK (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT) - -/* Page 0x30 ID Registers */ -#define CS42L42_SUB_REVID (CS42L42_PAGE_30 + 0x14) -#define CS42L42_MAX_REGISTER (CS42L42_PAGE_30 + 0x14) - -/* Defines for fracturing values spread across multiple registers */ -#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff) -#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8) -#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16) - -#define CS42L42_NUM_SUPPLIES 5 -#define CS42L42_BOOT_TIME_US 3000 -#define CS42L42_PLL_DIVOUT_TIME_US 800 -#define CS42L42_CLOCK_SWITCH_DELAY_US 150 -#define CS42L42_PLL_LOCK_POLL_US 250 -#define CS42L42_PLL_LOCK_TIMEOUT_US 1250 -#define CS42L42_HP_ADC_EN_TIME_US 20000 - -static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { - "VA", - "VP", - "VCP", - "VD_FILT", - "VL", -}; +#include <sound/cs42l42.h> +#include <sound/soc-component.h> +#include <sound/soc-dai.h> struct cs42l42_private { struct regmap *regmap; @@ -838,11 +30,13 @@ struct cs42l42_private { struct gpio_desc *reset_gpio; struct completion pdn_done; struct snd_soc_jack *jack; + struct mutex irq_lock; + int devid; + int irq; int pll_config; - int bclk; u32 sclk; + u32 bclk_ratio; u32 srate; - u8 pll_divout; u8 plug_state; u8 hs_type; u8 ts_inv; @@ -856,6 +50,25 @@ struct cs42l42_private { u8 hs_bias_sense_en; u8 stream_use; bool hp_adc_up_pending; + bool suspended; + bool init_done; }; +extern const struct regmap_range_cfg cs42l42_page_range; +extern const struct regmap_config cs42l42_regmap; +extern const struct snd_soc_component_driver cs42l42_soc_component; +extern struct snd_soc_dai_driver cs42l42_dai; + +bool cs42l42_readable_register(struct device *dev, unsigned int reg); +bool cs42l42_volatile_register(struct device *dev, unsigned int reg); + +int cs42l42_suspend(struct device *dev); +int cs42l42_resume(struct device *dev); +void cs42l42_resume_restore(struct device *dev); +int cs42l42_common_probe(struct cs42l42_private *cs42l42, + const struct snd_soc_component_driver *component_drv, + struct snd_soc_dai_driver *dai); +int cs42l42_init(struct cs42l42_private *cs42l42); +void cs42l42_common_remove(struct cs42l42_private *cs42l42); + #endif /* __CS42L42_H__ */ diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index 70260e0a8f09..85238339fbca 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,8 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); -static int cs42l51_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs42l51_i2c_probe(struct i2c_client *i2c) { struct regmap_config config; @@ -29,9 +28,9 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c, return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config)); } -static int cs42l51_i2c_remove(struct i2c_client *i2c) +static void cs42l51_i2c_remove(struct i2c_client *i2c) { - return cs42l51_remove(&i2c->dev); + cs42l51_remove(&i2c->dev); } static const struct dev_pm_ops cs42l51_pm_ops = { @@ -44,7 +43,7 @@ static struct i2c_driver cs42l51_i2c_driver = { .of_match_table = cs42l51_of_match, .pm = &cs42l51_pm_ops, }, - .probe = cs42l51_i2c_probe, + .probe_new = cs42l51_i2c_probe, .remove = cs42l51_i2c_remove, .id_table = cs42l51_i2c_id, }; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index c61b17dc2af8..51721edd8f53 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -51,11 +51,8 @@ struct cs42l51_private { struct regmap *regmap; }; -#define CS42L51_FORMATS ( \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define CS42L51_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -146,7 +143,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { 0, 0xA0, 96, adc_att_tlv), SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L51_ALC_PGA_CTL, CS42L51_ALC_PGB_CTL, - 0, 0x1A, 30, pga_tlv), + 0, 0x19, 30, pga_tlv), SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), @@ -603,7 +600,6 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg) @@ -793,14 +789,19 @@ error: } EXPORT_SYMBOL_GPL(cs42l51_probe); -int cs42l51_remove(struct device *dev) +void cs42l51_remove(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); + int ret; gpiod_set_value_cansleep(cs42l51->reset_gpio, 1); - return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), - cs42l51->supplies); + ret = regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies), + cs42l51->supplies); + if (ret) + dev_warn(dev, "Failed to disable all regulators (%pe)\n", + ERR_PTR(ret)); + } EXPORT_SYMBOL_GPL(cs42l51_remove); diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h index 9d06cf7f8876..a79343e8a54e 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h @@ -13,7 +13,7 @@ struct device; extern const struct regmap_config cs42l51_regmap; int cs42l51_probe(struct device *dev, struct regmap *regmap); -int cs42l51_remove(struct device *dev); +void cs42l51_remove(struct device *dev); int __maybe_unused cs42l51_suspend(struct device *dev); int __maybe_unused cs42l51_resume(struct device *dev); extern const struct of_device_id cs42l51_of_match[]; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 80161151b3f2..90bf535fc5a5 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -137,7 +137,9 @@ static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0); static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); -static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0); +static DECLARE_TLV_DB_SCALE(pass_tlv, -6000, 50, 0); + +static DECLARE_TLV_DB_SCALE(mix_tlv, -5150, 50, 0); static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0); @@ -351,7 +353,7 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv), SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL, - CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pga_tlv), + CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pass_tlv), SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), @@ -364,7 +366,7 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv), SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL, - 0, 0x19, 0x7F, ipd_tlv), + 0, 0x19, 0x7F, mix_tlv), SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0), @@ -1059,7 +1061,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l52 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Current and threshold powerup sequence Pg37 */ @@ -1086,8 +1087,7 @@ static const struct regmap_config cs42l52_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs42l52_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l52_i2c_probe(struct i2c_client *i2c_client) { struct cs42l52_private *cs42l52; struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev); @@ -1226,7 +1226,7 @@ static struct i2c_driver cs42l52_i2c_driver = { .of_match_table = cs42l52_of_match, }, .id_table = cs42l52_id, - .probe = cs42l52_i2c_probe, + .probe_new = cs42l52_i2c_probe, }; module_i2c_driver(cs42l52_i2c_driver); diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 3cf8a0b4478c..26066682c983 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -391,9 +391,9 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, - CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv), + CS42L56_HPB_VOLUME, 0, 0x44, 0x48, hl_tlv), SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, - CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv), + CS42L56_LOB_VOLUME, 0, 0x44, 0x48, hl_tlv), SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, 0, 0x00, 1, tone_tlv), @@ -1114,7 +1114,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l56 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs42l56_regmap = { @@ -1167,8 +1166,7 @@ static int cs42l56_handle_of_data(struct i2c_client *i2c_client, return 0; } -static int cs42l56_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l56_i2c_probe(struct i2c_client *i2c_client) { struct cs42l56_private *cs42l56; struct cs42l56_platform_data *pdata = @@ -1246,7 +1244,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); if (ret) { dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); - return ret; + goto err_enable; } devid = reg & CS42L56_CHIP_ID_MASK; @@ -1322,13 +1320,12 @@ err_enable: return ret; } -static int cs42l56_i2c_remove(struct i2c_client *client) +static void cs42l56_i2c_remove(struct i2c_client *client) { struct cs42l56_private *cs42l56 = i2c_get_clientdata(client); regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); - return 0; } static const struct of_device_id cs42l56_of_match[] = { @@ -1350,7 +1347,7 @@ static struct i2c_driver cs42l56_i2c_driver = { .of_match_table = cs42l56_of_match, }, .id_table = cs42l56_id, - .probe = cs42l56_i2c_probe, + .probe_new = cs42l56_i2c_probe, .remove = cs42l56_i2c_remove, }; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 018463f34e12..0a146319755a 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1256,7 +1256,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l73 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs42l73_regmap = { @@ -1274,8 +1273,7 @@ static const struct regmap_config cs42l73_regmap = { .use_single_write = true, }; -static int cs42l73_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int cs42l73_i2c_probe(struct i2c_client *i2c_client) { struct cs42l73_private *cs42l73; struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); @@ -1386,7 +1384,7 @@ static struct i2c_driver cs42l73_i2c_driver = { .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, - .probe = cs42l73_i2c_probe, + .probe_new = cs42l73_i2c_probe, }; diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c new file mode 100644 index 000000000000..f90d43996a51 --- /dev/null +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l83-i2c.c -- CS42L83 ALSA SoC audio driver for I2C + * + * Based on cs42l42-i2c.c: + * Copyright 2016, 2022 Cirrus Logic, Inc. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "cs42l42.h" + +static const struct reg_default cs42l83_reg_defaults[] = { + { CS42L42_FRZ_CTL, 0x00 }, + { CS42L42_SRC_CTL, 0x10 }, + { CS42L42_MCLK_CTL, 0x00 }, /* <- only deviation from CS42L42 */ + { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_SLOW_START_ENABLE, 0x70 }, + { CS42L42_I2C_DEBOUNCE, 0x88 }, + { CS42L42_I2C_STRETCH, 0x03 }, + { CS42L42_I2C_TIMEOUT, 0xB7 }, + { CS42L42_PWR_CTL1, 0xFF }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL1, 0x40 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_OSC_SWITCH, 0x00 }, + { CS42L42_RSENSE_CTL3, 0x1B }, + { CS42L42_TSENSE_CTL, 0x1B }, + { CS42L42_TSRS_INT_DISABLE, 0x00 }, + { CS42L42_HSDET_CTL1, 0x77 }, + { CS42L42_HSDET_CTL2, 0x00 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_HS_CLAMP_DISABLE, 0x00 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_SPDIF_CLK_CFG, 0x00 }, + { CS42L42_FSYNC_PW_LOWER, 0x00 }, + { CS42L42_FSYNC_PW_UPPER, 0x00 }, + { CS42L42_FSYNC_P_LOWER, 0xF9 }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x10 }, + { CS42L42_FS_RATE_EN, 0x00 }, + { CS42L42_IN_ASRC_CLK, 0x00 }, + { CS42L42_OUT_ASRC_CLK, 0x00 }, + { CS42L42_PLL_DIV_CFG1, 0x00 }, + { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, + { CS42L42_MIXER_INT_MASK, 0x0F }, + { CS42L42_SRC_INT_MASK, 0x0F }, + { CS42L42_ASP_RX_INT_MASK, 0x1F }, + { CS42L42_ASP_TX_INT_MASK, 0x0F }, + { CS42L42_CODEC_INT_MASK, 0x03 }, + { CS42L42_SRCPL_INT_MASK, 0x7F }, + { CS42L42_VPMON_INT_MASK, 0x01 }, + { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, + { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, + { CS42L42_PLL_CTL1, 0x00 }, + { CS42L42_PLL_DIV_FRAC0, 0x00 }, + { CS42L42_PLL_DIV_FRAC1, 0x00 }, + { CS42L42_PLL_DIV_FRAC2, 0x00 }, + { CS42L42_PLL_DIV_INT, 0x40 }, + { CS42L42_PLL_CTL3, 0x10 }, + { CS42L42_PLL_CAL_RATIO, 0x80 }, + { CS42L42_PLL_CTL4, 0x03 }, + { CS42L42_LOAD_DET_EN, 0x00 }, + { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, + { CS42L42_WAKE_CTL, 0xC0 }, + { CS42L42_ADC_DISABLE_MUTE, 0x00 }, + { CS42L42_TIPSENSE_CTL, 0x02 }, + { CS42L42_MISC_DET_CTL, 0x03 }, + { CS42L42_MIC_DET_CTL1, 0x1F }, + { CS42L42_MIC_DET_CTL2, 0x2F }, + { CS42L42_DET_INT1_MASK, 0xE0 }, + { CS42L42_DET_INT2_MASK, 0xFF }, + { CS42L42_HS_BIAS_CTL, 0xC2 }, + { CS42L42_ADC_CTL, 0x00 }, + { CS42L42_ADC_VOLUME, 0x00 }, + { CS42L42_ADC_WNF_HPF_CTL, 0x71 }, + { CS42L42_DAC_CTL1, 0x00 }, + { CS42L42_DAC_CTL2, 0x02 }, + { CS42L42_HP_CTL, 0x0D }, + { CS42L42_CLASSH_CTL, 0x07 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_EQ_COEF_IN0, 0x00 }, + { CS42L42_EQ_COEF_IN1, 0x00 }, + { CS42L42_EQ_COEF_IN2, 0x00 }, + { CS42L42_EQ_COEF_IN3, 0x00 }, + { CS42L42_EQ_COEF_RW, 0x00 }, + { CS42L42_EQ_COEF_OUT0, 0x00 }, + { CS42L42_EQ_COEF_OUT1, 0x00 }, + { CS42L42_EQ_COEF_OUT2, 0x00 }, + { CS42L42_EQ_COEF_OUT3, 0x00 }, + { CS42L42_EQ_INIT_STAT, 0x00 }, + { CS42L42_EQ_START_FILT, 0x00 }, + { CS42L42_EQ_MUTE_CTL, 0x00 }, + { CS42L42_SP_RX_CH_SEL, 0x04 }, + { CS42L42_SP_RX_ISOC_CTL, 0x04 }, + { CS42L42_SP_RX_FS, 0x8C }, + { CS42l42_SPDIF_CH_SEL, 0x0E }, + { CS42L42_SP_TX_ISOC_CTL, 0x04 }, + { CS42L42_SP_TX_FS, 0xCC }, + { CS42L42_SPDIF_SW_CTL1, 0x3F }, + { CS42L42_SRC_SDIN_FS, 0x40 }, + { CS42L42_SRC_SDOUT_FS, 0x40 }, + { CS42L42_SPDIF_CTL1, 0x01 }, + { CS42L42_SPDIF_CTL2, 0x00 }, + { CS42L42_SPDIF_CTL3, 0x00 }, + { CS42L42_SPDIF_CTL4, 0x42 }, + { CS42L42_ASP_TX_SZ_EN, 0x00 }, + { CS42L42_ASP_TX_CH_EN, 0x00 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x0F }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_EN, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, +}; + +/* + * This is all the same as for CS42L42 but we + * replace the on-reset register defaults. + */ +const struct regmap_config cs42l83_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = cs42l42_readable_register, + .volatile_reg = cs42l42_volatile_register, + + .ranges = &cs42l42_page_range, + .num_ranges = 1, + + .max_register = CS42L42_MAX_REGISTER, + .reg_defaults = cs42l83_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l83_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, +}; + +static int cs42l83_i2c_probe(struct i2c_client *i2c_client) +{ + struct device *dev = &i2c_client->dev; + struct cs42l42_private *cs42l83; + struct regmap *regmap; + int ret; + + cs42l83 = devm_kzalloc(dev, sizeof(*cs42l83), GFP_KERNEL); + if (!cs42l83) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c_client, &cs42l83_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap), + "regmap_init() failed\n"); + + cs42l83->devid = CS42L83_CHIP_ID; + cs42l83->dev = dev; + cs42l83->regmap = regmap; + cs42l83->irq = i2c_client->irq; + + ret = cs42l42_common_probe(cs42l83, &cs42l42_soc_component, &cs42l42_dai); + if (ret) + return ret; + + return cs42l42_init(cs42l83); +} + +static void cs42l83_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l83 = dev_get_drvdata(&i2c_client->dev); + + cs42l42_common_remove(cs42l83); +} + +static int __maybe_unused cs42l83_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); + + return 0; +} + +static const struct dev_pm_ops cs42l83_i2c_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume) +}; + +static const struct of_device_id __maybe_unused cs42l83_of_match[] = { + { .compatible = "cirrus,cs42l83", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l83_of_match); + +static struct i2c_driver cs42l83_i2c_driver = { + .driver = { + .name = "cs42l83", + .pm = &cs42l83_i2c_pm_ops, + .of_match_table = of_match_ptr(cs42l83_of_match), + }, + .probe_new = cs42l83_i2c_probe, + .remove = cs42l83_i2c_remove, +}; + +module_i2c_driver(cs42l83_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L83 I2C driver"); +MODULE_AUTHOR("Martin PoviÅ¡er <povik+lin@cutebit.org>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 0214e3ab9da0..bd80e9fc907f 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -17,8 +17,7 @@ #include "cs42xx8.h" -static int cs42xx8_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs42xx8_i2c_probe(struct i2c_client *i2c) { int ret = cs42xx8_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); @@ -31,11 +30,9 @@ static int cs42xx8_i2c_probe(struct i2c_client *i2c, return 0; } -static int cs42xx8_i2c_remove(struct i2c_client *i2c) +static void cs42xx8_i2c_remove(struct i2c_client *i2c) { pm_runtime_disable(&i2c->dev); - - return 0; } static struct i2c_device_id cs42xx8_i2c_id[] = { @@ -51,7 +48,7 @@ static struct i2c_driver cs42xx8_i2c_driver = { .pm = &cs42xx8_pm, .of_match_table = cs42xx8_of_match, }, - .probe = cs42xx8_i2c_probe, + .probe_new = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, .id_table = cs42xx8_i2c_id, }; diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 5d6ef660f851..d14eb2f6e1dd 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -497,7 +497,6 @@ static const struct snd_soc_component_driver cs42xx8_driver = { .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct cs42xx8_driver_data cs42448_data = { diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 44b20c1ef851..db39abb2a31b 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -712,30 +712,30 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, case CS43130_ASP_PCM_DAI: case CS43130_ASP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; case CS43130_XSP_DOP_DAI: regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, - (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >> CS43130_SP_M_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, - (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >> CS43130_SP_M_MSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, - (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >> CS43130_SP_N_LSB_DATA_SHIFT); regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, - (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >> CS43130_SP_N_MSB_DATA_SHIFT); break; default: @@ -1666,10 +1666,9 @@ static int cs43130_show_dc(struct device *dev, char *buf, u8 ch) struct cs43130_private *cs43130 = i2c_get_clientdata(client); if (!cs43130->hpload_done) - return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + return sysfs_emit(buf, "NO_HPLOAD\n"); else - return scnprintf(buf, PAGE_SIZE, "%u\n", - cs43130->hpload_dc[ch]); + return sysfs_emit(buf, "%u\n", cs43130->hpload_dc[ch]); } static ssize_t hpload_dc_l_show(struct device *dev, @@ -1705,8 +1704,8 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) if (cs43130->hpload_done && cs43130->ac_meas) { for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) { - tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n", - cs43130->hpload_ac[i][ch]); + tmp = sysfs_emit_at(buf, j, "%u\n", + cs43130->hpload_ac[i][ch]); if (!tmp) break; @@ -1715,7 +1714,7 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) return j; } else { - return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + return sysfs_emit(buf, "NO_HPLOAD\n"); } } @@ -2303,7 +2302,7 @@ static int cs43130_probe(struct snd_soc_component *component) } ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, - &cs43130->jack, NULL, 0); + &cs43130->jack); if (ret < 0) { dev_err(component->dev, "Cannot create jack\n"); return ret; @@ -2345,7 +2344,6 @@ static struct snd_soc_component_driver soc_component_dev_cs43130 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs43130_regmap = { @@ -2418,8 +2416,7 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client, return 0; } -static int cs43130_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs43130_i2c_probe(struct i2c_client *client) { struct cs43130_private *cs43130; int ret; @@ -2585,7 +2582,7 @@ err_supplies: return ret; } -static int cs43130_i2c_remove(struct i2c_client *client) +static void cs43130_i2c_remove(struct i2c_client *client) { struct cs43130_private *cs43130 = i2c_get_clientdata(client); @@ -2612,8 +2609,6 @@ static int cs43130_i2c_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); - - return 0; } static int __maybe_unused cs43130_runtime_suspend(struct device *dev) @@ -2702,7 +2697,7 @@ static struct i2c_driver cs43130_i2c_driver = { .pm = &cs43130_runtime_pm, }, .id_table = cs43130_i2c_id, - .probe = cs43130_i2c_probe, + .probe_new = cs43130_i2c_probe, .remove = cs43130_i2c_remove, }; diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index e62d671e95bb..1dd893674313 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -10,6 +10,8 @@ #ifndef __CS43130_H__ #define __CS43130_H__ +#include <linux/math.h> + /* CS43130 registers addresses */ /* all reg address is shifted by a byte for control byte to be LSB */ #define CS43130_FIRSTREG 0x010000 @@ -372,97 +374,96 @@ enum cs43130_dai_id { }; struct cs43130_clk_gen { - unsigned int mclk_int; - int fs; - u16 den; - u16 num; + unsigned int mclk_int; + int fs; + struct u16_fract v; }; /* frm_size = 16 */ static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { - {22579200, 32000, 441, 10,}, - {22579200, 44100, 32, 1,}, - {22579200, 48000, 147, 5,}, - {22579200, 88200, 16, 1,}, - {22579200, 96000, 147, 10,}, - {22579200, 176400, 8, 1,}, - {22579200, 192000, 147, 20,}, - {22579200, 352800, 4, 1,}, - {22579200, 384000, 147, 40,}, - {24576000, 32000, 48, 1,}, - {24576000, 44100, 5120, 147,}, - {24576000, 48000, 32, 1,}, - {24576000, 88200, 2560, 147,}, - {24576000, 96000, 16, 1,}, - {24576000, 176400, 1280, 147,}, - {24576000, 192000, 8, 1,}, - {24576000, 352800, 640, 147,}, - {24576000, 384000, 4, 1,}, + { 22579200, 32000, .v = { 441, 10, }, }, + { 22579200, 44100, .v = { 32, 1, }, }, + { 22579200, 48000, .v = { 147, 5, }, }, + { 22579200, 88200, .v = { 16, 1, }, }, + { 22579200, 96000, .v = { 147, 10, }, }, + { 22579200, 176400, .v = { 8, 1, }, }, + { 22579200, 192000, .v = { 147, 20, }, }, + { 22579200, 352800, .v = { 4, 1, }, }, + { 22579200, 384000, .v = { 147, 40, }, }, + { 24576000, 32000, .v = { 48, 1, }, }, + { 24576000, 44100, .v = { 5120, 147, }, }, + { 24576000, 48000, .v = { 32, 1, }, }, + { 24576000, 88200, .v = { 2560, 147, }, }, + { 24576000, 96000, .v = { 16, 1, }, }, + { 24576000, 176400, .v = { 1280, 147, }, }, + { 24576000, 192000, .v = { 8, 1, }, }, + { 24576000, 352800, .v = { 640, 147, }, }, + { 24576000, 384000, .v = { 4, 1, }, }, }; /* frm_size = 32 */ static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { - {22579200, 32000, 441, 20,}, - {22579200, 44100, 16, 1,}, - {22579200, 48000, 147, 10,}, - {22579200, 88200, 8, 1,}, - {22579200, 96000, 147, 20,}, - {22579200, 176400, 4, 1,}, - {22579200, 192000, 147, 40,}, - {22579200, 352800, 2, 1,}, - {22579200, 384000, 147, 80,}, - {24576000, 32000, 24, 1,}, - {24576000, 44100, 2560, 147,}, - {24576000, 48000, 16, 1,}, - {24576000, 88200, 1280, 147,}, - {24576000, 96000, 8, 1,}, - {24576000, 176400, 640, 147,}, - {24576000, 192000, 4, 1,}, - {24576000, 352800, 320, 147,}, - {24576000, 384000, 2, 1,}, + { 22579200, 32000, .v = { 441, 20, }, }, + { 22579200, 44100, .v = { 16, 1, }, }, + { 22579200, 48000, .v = { 147, 10, }, }, + { 22579200, 88200, .v = { 8, 1, }, }, + { 22579200, 96000, .v = { 147, 20, }, }, + { 22579200, 176400, .v = { 4, 1, }, }, + { 22579200, 192000, .v = { 147, 40, }, }, + { 22579200, 352800, .v = { 2, 1, }, }, + { 22579200, 384000, .v = { 147, 80, }, }, + { 24576000, 32000, .v = { 24, 1, }, }, + { 24576000, 44100, .v = { 2560, 147, }, }, + { 24576000, 48000, .v = { 16, 1, }, }, + { 24576000, 88200, .v = { 1280, 147, }, }, + { 24576000, 96000, .v = { 8, 1, }, }, + { 24576000, 176400, .v = { 640, 147, }, }, + { 24576000, 192000, .v = { 4, 1, }, }, + { 24576000, 352800, .v = { 320, 147, }, }, + { 24576000, 384000, .v = { 2, 1, }, }, }; /* frm_size = 48 */ static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { - {22579200, 32000, 147, 100,}, - {22579200, 44100, 32, 3,}, - {22579200, 48000, 49, 5,}, - {22579200, 88200, 16, 3,}, - {22579200, 96000, 49, 10,}, - {22579200, 176400, 8, 3,}, - {22579200, 192000, 49, 20,}, - {22579200, 352800, 4, 3,}, - {22579200, 384000, 49, 40,}, - {24576000, 32000, 16, 1,}, - {24576000, 44100, 5120, 441,}, - {24576000, 48000, 32, 3,}, - {24576000, 88200, 2560, 441,}, - {24576000, 96000, 16, 3,}, - {24576000, 176400, 1280, 441,}, - {24576000, 192000, 8, 3,}, - {24576000, 352800, 640, 441,}, - {24576000, 384000, 4, 3,}, + { 22579200, 32000, .v = { 147, 100, }, }, + { 22579200, 44100, .v = { 32, 3, }, }, + { 22579200, 48000, .v = { 49, 5, }, }, + { 22579200, 88200, .v = { 16, 3, }, }, + { 22579200, 96000, .v = { 49, 10, }, }, + { 22579200, 176400, .v = { 8, 3, }, }, + { 22579200, 192000, .v = { 49, 20, }, }, + { 22579200, 352800, .v = { 4, 3, }, }, + { 22579200, 384000, .v = { 49, 40, }, }, + { 24576000, 32000, .v = { 16, 1, }, }, + { 24576000, 44100, .v = { 5120, 441, }, }, + { 24576000, 48000, .v = { 32, 3, }, }, + { 24576000, 88200, .v = { 2560, 441, }, }, + { 24576000, 96000, .v = { 16, 3, }, }, + { 24576000, 176400, .v = { 1280, 441, }, }, + { 24576000, 192000, .v = { 8, 3, }, }, + { 24576000, 352800, .v = { 640, 441, }, }, + { 24576000, 384000, .v = { 4, 3, }, }, }; /* frm_size = 64 */ static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { - {22579200, 32000, 441, 40,}, - {22579200, 44100, 8, 1,}, - {22579200, 48000, 147, 20,}, - {22579200, 88200, 4, 1,}, - {22579200, 96000, 147, 40,}, - {22579200, 176400, 2, 1,}, - {22579200, 192000, 147, 80,}, - {22579200, 352800, 1, 1,}, - {24576000, 32000, 12, 1,}, - {24576000, 44100, 1280, 147,}, - {24576000, 48000, 8, 1,}, - {24576000, 88200, 640, 147,}, - {24576000, 96000, 4, 1,}, - {24576000, 176400, 320, 147,}, - {24576000, 192000, 2, 1,}, - {24576000, 352800, 160, 147,}, - {24576000, 384000, 1, 1,}, + { 22579200, 32000, .v = { 441, 40, }, }, + { 22579200, 44100, .v = { 8, 1, }, }, + { 22579200, 48000, .v = { 147, 20, }, }, + { 22579200, 88200, .v = { 4, 1, }, }, + { 22579200, 96000, .v = { 147, 40, }, }, + { 22579200, 176400, .v = { 2, 1, }, }, + { 22579200, 192000, .v = { 147, 80, }, }, + { 22579200, 352800, .v = { 1, 1, }, }, + { 24576000, 32000, .v = { 12, 1, }, }, + { 24576000, 44100, .v = { 1280, 147, }, }, + { 24576000, 48000, .v = { 8, 1, }, }, + { 24576000, 88200, .v = { 640, 147, }, }, + { 24576000, 96000, .v = { 4, 1, }, }, + { 24576000, 176400, .v = { 320, 147, }, }, + { 24576000, 192000, .v = { 2, 1, }, }, + { 24576000, 352800, .v = { 160, 147, }, }, + { 24576000, 384000, .v = { 1, 1, }, }, }; struct cs43130_bitwidth_map { diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index 29d05e32d341..ac1696034846 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -202,7 +202,6 @@ static const struct snd_soc_component_driver soc_component_cs4341 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id __maybe_unused cs4341_dt_ids[] = { @@ -225,8 +224,7 @@ static int cs4341_probe(struct device *dev) } #if IS_ENABLED(CONFIG_I2C) -static int cs4341_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cs4341_i2c_probe(struct i2c_client *i2c) { struct cs4341_priv *cs4341; @@ -260,7 +258,7 @@ static struct i2c_driver cs4341_i2c_driver = { .name = "cs4341-i2c", .of_match_table = of_match_ptr(cs4341_dt_ids), }, - .probe = cs4341_i2c_probe, + .probe_new = cs4341_i2c_probe, .id_table = cs4341_i2c_id, }; #endif diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 786c69a8ec4a..ba94ffd0a7e4 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -223,12 +223,9 @@ static const struct snd_soc_dapm_route cs4349_routes[] = { {"OutputB", NULL, "HiFi DAC"}, }; -#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ +#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) #define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000 @@ -263,7 +260,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4349 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config cs4349_regmap = { @@ -278,8 +274,7 @@ static const struct regmap_config cs4349_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int cs4349_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs4349_i2c_probe(struct i2c_client *client) { struct cs4349_private *cs4349; int ret; @@ -310,14 +305,12 @@ static int cs4349_i2c_probe(struct i2c_client *client, &cs4349_dai, 1); } -static int cs4349_i2c_remove(struct i2c_client *client) +static void cs4349_i2c_remove(struct i2c_client *client) { struct cs4349_private *cs4349 = i2c_get_clientdata(client); /* Hold down reset */ gpiod_set_value_cansleep(cs4349->reset_gpio, 0); - - return 0; } #ifdef CONFIG_PM @@ -382,7 +375,7 @@ static struct i2c_driver cs4349_i2c_driver = { .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, - .probe = cs4349_i2c_probe, + .probe_new = cs4349_i2c_probe, .remove = cs4349_i2c_remove, }; diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index 391fd7da331f..06c4214382e3 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -122,6 +122,9 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, snd_soc_kcontrol_component(kcontrol); struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode) + return 0; + switch (ucontrol->value.integer.value[0]) { case 0: /* Set IN1 to normal mode */ @@ -150,7 +153,7 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, break; } - return 0; + return 1; } static const struct snd_kcontrol_new cs47l15_snd_controls[] = { @@ -1353,7 +1356,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l15 = { .num_dapm_routes = ARRAY_SIZE(cs47l15_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l15_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 6356f81aafc5..f9a2b865d717 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1203,7 +1203,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l24 = { .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l24_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index db2f844b8b17..c1032d6c9143 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1638,7 +1638,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l35 = { .num_dapm_routes = ARRAY_SIZE(cs47l35_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l35_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index d4fedc5ad516..215d8211aa59 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2582,7 +2582,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l85 = { .num_dapm_routes = ARRAY_SIZE(cs47l85_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l85_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 5aec937a2462..1ad6526c7871 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2497,7 +2497,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l90 = { .num_dapm_routes = ARRAY_SIZE(cs47l90_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l90_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index a1b8dcdb9f7b..fe576d64e089 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -119,7 +119,13 @@ static int cs47l92_put_demux(struct snd_kcontrol *kcontrol, end: snd_soc_dapm_mutex_unlock(dapm); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + if (ret < 0) { + dev_err(madera->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum, @@ -1958,7 +1964,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l92 = { .num_dapm_routes = ARRAY_SIZE(cs47l92_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cs47l92_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index f2087bd38dbc..69db0013d243 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -348,22 +348,22 @@ static const struct snd_kcontrol_new cs53l30_snd_controls[] = { SOC_ENUM("ADC2 NG Delay", adc2_ng_delay_enum), SOC_SINGLE_SX_TLV("ADC1A PGA Volume", - CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC1B PGA Volume", - CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC2A PGA Volume", - CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC2B PGA Volume", - CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), + CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), SOC_SINGLE_SX_TLV("ADC1A Digital Volume", - CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC1B Digital Volume", - CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC2A Digital Volume", - CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), SOC_SINGLE_SX_TLV("ADC2B Digital Volume", - CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), + CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), }; static const struct snd_soc_dapm_widget cs53l30_dapm_widgets[] = { @@ -899,7 +899,6 @@ static const struct snd_soc_component_driver cs53l30_driver = { .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct regmap_config cs53l30_regmap = { @@ -918,8 +917,7 @@ static struct regmap_config cs53l30_regmap = { .use_single_write = true, }; -static int cs53l30_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs53l30_i2c_probe(struct i2c_client *client) { const struct device_node *np = client->dev.of_node; struct device *dev = &client->dev; @@ -1045,7 +1043,7 @@ error_supplies: return ret; } -static int cs53l30_i2c_remove(struct i2c_client *client) +static void cs53l30_i2c_remove(struct i2c_client *client) { struct cs53l30_private *cs53l30 = i2c_get_clientdata(client); @@ -1054,8 +1052,6 @@ static int cs53l30_i2c_remove(struct i2c_client *client) regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), cs53l30->supplies); - - return 0; } #ifdef CONFIG_PM @@ -1125,7 +1121,7 @@ static struct i2c_driver cs53l30_i2c_driver = { .pm = &cs53l30_runtime_pm, }, .id_table = cs53l30_id, - .probe = cs53l30_i2c_probe, + .probe_new = cs53l30_i2c_probe, .remove = cs53l30_i2c_remove, }; diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 1af0bf5f1e2f..43c0cac0ec9e 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -411,7 +411,6 @@ static const struct snd_soc_component_driver cx20442_component_dev = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int cx20442_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 1f5c57fab1d8..5deceaa89282 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -710,22 +710,19 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x) regdbt2.ulval = 0xac; - /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: reg2.r.tx_master = 1; reg3.r.rx_master = 1; - dev_dbg(dev, "Sets Master mode\n"); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg2.r.tx_master = 0; reg3.r.rx_master = 0; - dev_dbg(dev, "Sets Slave mode\n"); break; default: - dev_err(dev, "Unsupported DAI master mode\n"); + dev_err(dev, "Unsupported DAI clocking mode\n"); return -EINVAL; } @@ -1009,9 +1006,9 @@ static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(dev, "set_dai_fmt- %08x\n", fmt); /* set master/slave */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: break; default: @@ -1527,6 +1524,7 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = { .num_dapm_widgets = ARRAY_SIZE(cx2072x_dapm_widgets), .dapm_routes = cx2072x_intercon, .num_dapm_routes = ARRAY_SIZE(cx2072x_intercon), + .endianness = 1, }; /* @@ -1626,8 +1624,7 @@ static int __maybe_unused cx2072x_runtime_resume(struct device *dev) return clk_prepare_enable(cx2072x->mclk); } -static int cx2072x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int cx2072x_i2c_probe(struct i2c_client *i2c) { struct cx2072x_priv *cx2072x; unsigned int ven_id, rev_id; @@ -1676,10 +1673,9 @@ static int cx2072x_i2c_probe(struct i2c_client *i2c, return 0; } -static int cx2072x_i2c_remove(struct i2c_client *i2c) +static void cx2072x_i2c_remove(struct i2c_client *i2c) { pm_runtime_disable(&i2c->dev); - return 0; } static const struct i2c_device_id cx2072x_i2c_id[] = { @@ -1710,7 +1706,7 @@ static struct i2c_driver cx2072x_i2c_driver = { .acpi_match_table = ACPI_PTR(cx2072x_acpi_match), .pm = &cx2072x_runtime_pm, }, - .probe = cx2072x_i2c_probe, + .probe_new = cx2072x_i2c_probe, .remove = cx2072x_i2c_remove, .id_table = cx2072x_i2c_id, }; diff --git a/sound/soc/codecs/cx2072x.h b/sound/soc/codecs/cx2072x.h index ebdd567fa225..09e3a92b184f 100644 --- a/sound/soc/codecs/cx2072x.h +++ b/sound/soc/codecs/cx2072x.h @@ -177,7 +177,7 @@ #define CX2072X_PLBK_DRC_PARM_LEN 9 #define CX2072X_CLASSD_AMP_LEN 6 -/* DAI interfae type */ +/* DAI interface type */ #define CX2072X_DAI_HIFI 1 #define CX2072X_DAI_DSP 2 #define CX2072X_DAI_DSP_PWM 3 /* 4 ch, including mic and AEC */ diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 8af344b2fdbf..f838466bfebf 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7210 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #if IS_ENABLED(CONFIG_I2C) @@ -1206,8 +1205,7 @@ static const struct regmap_config da7210_regmap_config_i2c = { .cache_type = REGCACHE_RBTREE, }; -static int da7210_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7210_i2c_probe(struct i2c_client *i2c) { struct da7210_priv *da7210; int ret; @@ -1250,7 +1248,7 @@ static struct i2c_driver da7210_i2c_driver = { .driver = { .name = "da7210", }, - .probe = da7210_i2c_probe, + .probe_new = da7210_i2c_probe, .id_table = da7210_i2c_id, }; #endif @@ -1336,6 +1334,8 @@ static int __init da7210_modinit(void) int ret = 0; #if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&da7210_i2c_driver); + if (ret) + return ret; #endif #if defined(CONFIG_SPI_MASTER) ret = spi_register_driver(&da7210_spi_driver); diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3ab89387b4e6..544ccbcfc884 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1922,7 +1922,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config da7213_regmap_config = { @@ -1946,8 +1945,7 @@ static const char *da7213_supply_names[DA7213_NUM_SUPPLIES] = { [DA7213_SUPPLY_VDDIO] = "VDDIO", }; -static int da7213_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7213_i2c_probe(struct i2c_client *i2c) { struct da7213_priv *da7213; int i, ret; @@ -2040,7 +2038,7 @@ static struct i2c_driver da7213_i2c_driver = { .acpi_match_table = ACPI_PTR(da7213_acpi_match), .pm = &da7213_pm, }, - .probe = da7213_i2c_probe, + .probe_new = da7213_i2c_probe, .id_table = da7213_i2c_id, }; diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index ea426d986d4c..91372909d184 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3040,7 +3040,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7218 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -3258,8 +3257,19 @@ static const struct regmap_config da7218_regmap_config = { * I2C layer */ -static int da7218_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id da7218_i2c_id[]; + +static inline int da7218_i2c_get_id(struct i2c_client *i2c) +{ + const struct i2c_device_id *id = i2c_match_id(da7218_i2c_id, i2c); + + if (id) + return (uintptr_t)id->driver_data; + else + return -EINVAL; +} + +static int da7218_i2c_probe(struct i2c_client *i2c) { struct da7218_priv *da7218; int ret; @@ -3273,7 +3283,7 @@ static int da7218_i2c_probe(struct i2c_client *i2c, if (i2c->dev.of_node) da7218->dev_id = da7218_of_get_id(&i2c->dev); else - da7218->dev_id = id->driver_data; + da7218->dev_id = da7218_i2c_get_id(i2c); if ((da7218->dev_id != DA7217_DEV_ID) && (da7218->dev_id != DA7218_DEV_ID)) { @@ -3311,7 +3321,7 @@ static struct i2c_driver da7218_i2c_driver = { .name = "da7218", .of_match_table = da7218_of_match, }, - .probe = da7218_i2c_probe, + .probe_new = da7218_i2c_probe, .id_table = da7218_i2c_id, }; diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 7998fdd3b378..bba73c44c219 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -60,6 +60,9 @@ static void da7219_aad_btn_det_work(struct work_struct *work) bool micbias_up = false; int retries = 0; + /* Disable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00); + /* Drive headphones/lineout */ snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, @@ -153,6 +156,9 @@ static void da7219_aad_hptest_work(struct work_struct *work) tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); } + /* Disable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00); + /* Ensure gain ramping at fastest rate */ gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL); snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8); @@ -428,6 +434,10 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) mask |= DA7219_AAD_REPORT_ALL_MASK; da7219_aad->jack_inserted = false; + /* Cancel any pending work */ + cancel_work_sync(&da7219_aad->btn_det_work); + cancel_work_sync(&da7219_aad->hptest_work); + /* Un-drive headphones/lineout */ snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, 0); @@ -444,9 +454,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) snd_soc_dapm_disable_pin(dapm, "Mic Bias"); snd_soc_dapm_sync(dapm); - /* Cancel any pending work */ - cancel_work_sync(&da7219_aad->btn_det_work); - cancel_work_sync(&da7219_aad->hptest_work); + /* Enable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); } } @@ -899,6 +908,9 @@ int da7219_aad_init(struct snd_soc_component *component) snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, DA7219_BUTTON_CONFIG_MASK, 0); + /* Enable ground switch */ + snd_soc_component_update_bits(component, 0xFB, 0x01, 0x01); + INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work); INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work); diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 13009d08b09a..4746c8700451 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -446,7 +446,7 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - __le16 val; + __le16 val_new, val_old; int ret; /* @@ -454,13 +454,19 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, * Therefore we need to convert to little endian here to align with * HW registers. */ - val = cpu_to_le16(ucontrol->value.integer.value[0]); + val_new = cpu_to_le16(ucontrol->value.integer.value[0]); mutex_lock(&da7219->ctrl_lock); - ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val)); + ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old)); + if (ret == 0 && (val_old != val_new)) + ret = regmap_raw_write(da7219->regmap, reg, + &val_new, sizeof(val_new)); mutex_unlock(&da7219->ctrl_lock); - return ret; + if (ret < 0) + return ret; + + return val_old != val_new; } @@ -2190,6 +2196,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) dai_clk_lookup = clkdev_hw_create(dai_clk_hw, init.name, "%s", dev_name(dev)); if (!dai_clk_lookup) { + clk_hw_unregister(dai_clk_hw); ret = -ENOMEM; goto err; } else { @@ -2211,12 +2218,12 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) return 0; err: - do { + while (--i >= 0) { if (da7219->dai_clks_lookup[i]) clkdev_drop(da7219->dai_clks_lookup[i]); clk_hw_unregister(&da7219->dai_clks_hw[i]); - } while (i-- > 0); + } if (np) kfree(da7219->clk_hw_data); @@ -2641,7 +2648,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -2649,8 +2655,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = { * I2C layer */ -static int da7219_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da7219_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct da7219_priv *da7219; @@ -2688,11 +2693,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c, return ret; } -static int da7219_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da7219_i2c_id[] = { { "da7219", }, { } @@ -2705,8 +2705,7 @@ static struct i2c_driver da7219_i2c_driver = { .of_match_table = of_match_ptr(da7219_of_match), .acpi_match_table = ACPI_PTR(da7219_acpi_match), }, - .probe = da7219_i2c_probe, - .remove = da7219_i2c_remove, + .probe_new = da7219_i2c_probe, .id_table = da7219_i2c_id, }; diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 42d6a3fc3af5..2c5b0b74201c 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1503,11 +1503,9 @@ static const struct snd_soc_component_driver soc_component_dev_da732x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int da732x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da732x_i2c_probe(struct i2c_client *i2c) { struct da732x_priv *da732x; unsigned int reg; @@ -1547,11 +1545,6 @@ err: return ret; } -static int da732x_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id da732x_i2c_id[] = { { "da7320", 0}, { } @@ -1562,8 +1555,7 @@ static struct i2c_driver da732x_i2c_driver = { .driver = { .name = "da7320", }, - .probe = da732x_i2c_probe, - .remove = da732x_i2c_remove, + .probe_new = da732x_i2c_probe, .id_table = da732x_i2c_id, }; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index a9676b261129..28043b4530df 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1460,7 +1460,6 @@ static const struct snd_soc_component_driver soc_component_dev_da9055 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config da9055_regmap_config = { @@ -1473,8 +1472,7 @@ static const struct regmap_config da9055_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int da9055_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int da9055_i2c_probe(struct i2c_client *i2c) { struct da9055_priv *da9055; struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev); @@ -1533,7 +1531,7 @@ static struct i2c_driver da9055_i2c_driver = { .name = "da9055-codec", .of_match_table = of_match_ptr(da9055_of_match), }, - .probe = da9055_i2c_probe, + .probe_new = da9055_i2c_probe, .id_table = da9055_i2c_id, }; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 5d079d90fd3b..4fd6f97e5a49 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -82,7 +82,10 @@ static struct snd_soc_dai_driver dmic_dai = { .rates = SNDRV_PCM_RATE_CONTINUOUS, .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE - | SNDRV_PCM_FMTBIT_S16_LE, + | SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_DSD_U8 + | SNDRV_PCM_FMTBIT_DSD_U16_LE + | SNDRV_PCM_FMTBIT_DSD_U32_LE, }, .ops = &dmic_dai_ops, }; @@ -137,7 +140,6 @@ static const struct snd_soc_component_driver soc_dmic = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int dmic_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c index e2b79879354b..f5150d2f95da 100644 --- a/sound/soc/codecs/es7134.c +++ b/sound/soc/codecs/es7134.c @@ -94,7 +94,7 @@ static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) SND_SOC_DAIFMT_MASTER_MASK); if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS)) { + SND_SOC_DAIFMT_CBC_CFC)) { dev_err(codec_dai->dev, "Invalid DAI format\n"); return -EINVAL; } @@ -213,7 +213,6 @@ static const struct snd_soc_component_driver es7134_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver es7154_dai = { diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c index 2344a0b03518..339553cfbb48 100644 --- a/sound/soc/codecs/es7241.c +++ b/sound/soc/codecs/es7241.c @@ -29,7 +29,7 @@ struct es7241_data { struct gpio_desc *m1; unsigned int fmt; unsigned int mclk; - bool is_slave; + bool is_consumer; const struct es7241_chip *chip; }; @@ -46,9 +46,9 @@ static void es7241_set_mode(struct es7241_data *priv, int m0, int m1) gpiod_set_value_cansleep(priv->reset, 1); } -static int es7241_set_slave_mode(struct es7241_data *priv, - const struct es7241_clock_mode *mode, - unsigned int mfs) +static int es7241_set_consumer_mode(struct es7241_data *priv, + const struct es7241_clock_mode *mode, + unsigned int mfs) { int j; @@ -67,9 +67,9 @@ out_ok: return 0; } -static int es7241_set_master_mode(struct es7241_data *priv, - const struct es7241_clock_mode *mode, - unsigned int mfs) +static int es7241_set_provider_mode(struct es7241_data *priv, + const struct es7241_clock_mode *mode, + unsigned int mfs) { /* * We can't really set clock ratio, if the mclk/lrclk is different @@ -98,10 +98,10 @@ static int es7241_hw_params(struct snd_pcm_substream *substream, if (rate < mode->rate_min || rate >= mode->rate_max) continue; - if (priv->is_slave) - return es7241_set_slave_mode(priv, mode, mfs); + if (priv->is_consumer) + return es7241_set_consumer_mode(priv, mode, mfs); else - return es7241_set_master_mode(priv, mode, mfs); + return es7241_set_provider_mode(priv, mode, mfs); } /* should not happen */ @@ -136,12 +136,12 @@ static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - priv->is_slave = true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + priv->is_consumer = true; break; - case SND_SOC_DAIFMT_CBM_CFM: - priv->is_slave = false; + case SND_SOC_DAIFMT_CBP_CFP: + priv->is_consumer = false; break; default: @@ -232,7 +232,6 @@ static const struct snd_soc_component_driver es7241_component_driver = { .num_dapm_routes = ARRAY_SIZE(es7241_dapm_routes), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv) @@ -255,7 +254,6 @@ static int es7241_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct es7241_data *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -271,28 +269,19 @@ static int es7241_probe(struct platform_device *pdev) es7241_parse_fmt(dev, priv); priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(priv->reset)) { - err = PTR_ERR(priv->reset); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'reset' gpio: %d", err); - return err; - } + if (IS_ERR(priv->reset)) + return dev_err_probe(dev, PTR_ERR(priv->reset), + "Failed to get 'reset' gpio"); priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW); - if (IS_ERR(priv->m0)) { - err = PTR_ERR(priv->m0); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'm0' gpio: %d", err); - return err; - } + if (IS_ERR(priv->m0)) + return dev_err_probe(dev, PTR_ERR(priv->m0), + "Failed to get 'm0' gpio"); priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW); - if (IS_ERR(priv->m1)) { - err = PTR_ERR(priv->m1); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'm1' gpio: %d", err); - return err; - } + if (IS_ERR(priv->m1)) + return dev_err_probe(dev, PTR_ERR(priv->m1), + "Failed to get 'm1' gpio"); return devm_snd_soc_register_component(&pdev->dev, &es7241_component_driver, diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 8f30a3ea8bfe..056c3082fe02 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -401,10 +401,8 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 clksw; u8 mask; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - dev_err(component->dev, "Codec driver only supports slave mode\n"); - return -EINVAL; - } + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP) + serdata1 |= ES8316_SERDATA1_MASTER; if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { dev_err(component->dev, "Codec driver only supports I2S format\n"); @@ -464,6 +462,8 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); u8 wordlen = 0; + u8 bclk_divider; + u16 lrck_divider; int i; /* Validate supported sample rates that are autodetected from MCLK */ @@ -477,19 +477,24 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, } if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS) return -EINVAL; - + lrck_divider = es8316->sysclk / params_rate(params); + bclk_divider = lrck_divider / 4; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: wordlen = ES8316_SERDATA2_LEN_16; + bclk_divider /= 16; break; case SNDRV_PCM_FORMAT_S20_3LE: wordlen = ES8316_SERDATA2_LEN_20; + bclk_divider /= 20; break; case SNDRV_PCM_FORMAT_S24_LE: wordlen = ES8316_SERDATA2_LEN_24; + bclk_divider /= 24; break; case SNDRV_PCM_FORMAT_S32_LE: wordlen = ES8316_SERDATA2_LEN_32; + bclk_divider /= 32; break; default: return -EINVAL; @@ -499,6 +504,11 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, ES8316_SERDATA2_LEN_MASK, wordlen); snd_soc_component_update_bits(component, ES8316_SERDATA_ADC, ES8316_SERDATA2_LEN_MASK, wordlen); + snd_soc_component_update_bits(component, ES8316_SERDATA1, 0x1f, bclk_divider); + snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV1, 0x0f, lrck_divider >> 8); + snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV2, 0xff, lrck_divider & 0xff); + snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV1, 0x0f, lrck_divider >> 8); + snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV2, 0xff, lrck_divider & 0xff); return 0; } @@ -757,9 +767,31 @@ static void es8316_remove(struct snd_soc_component *component) clk_disable_unprepare(es8316->mclk); } +static int es8316_resume(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8316->regmap, false); + regcache_sync(es8316->regmap); + + return 0; +} + +static int es8316_suspend(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8316->regmap, true); + regcache_mark_dirty(es8316->regmap); + + return 0; +} + static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, .remove = es8316_remove, + .resume = es8316_resume, + .suspend = es8316_suspend, .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), @@ -769,7 +801,6 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .num_dapm_routes = ARRAY_SIZE(es8316_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_range es8316_volatile_ranges[] = { @@ -784,13 +815,14 @@ static const struct regmap_access_table es8316_volatile_table = { static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, + .use_single_read = true, + .use_single_write = true, .max_register = 0x53, .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, }; -static int es8316_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int es8316_i2c_probe(struct i2c_client *i2c_client) { struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; @@ -852,7 +884,7 @@ static struct i2c_driver es8316_i2c_driver = { .acpi_match_table = ACPI_PTR(es8316_acpi_match), .of_match_table = of_match_ptr(es8316_of_match), }, - .probe = es8316_i2c_probe, + .probe_new = es8316_i2c_probe, .id_table = es8316_i2c_id, }; module_i2c_driver(es8316_i2c_driver); diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c new file mode 100755 index 000000000000..87c1cc16592b --- /dev/null +++ b/sound/soc/codecs/es8326.c @@ -0,0 +1,905 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// es8326.c -- es8326 ALSA SoC audio driver +// Copyright Everest Semiconductor Co., Ltd +// +// Authors: David Yang <yangxiaohua@everest-semi.com> +// + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include "es8326.h" + +struct es8326_priv { + struct clk *mclk; + struct i2c_client *i2c; + struct regmap *regmap; + struct snd_soc_component *component; + struct delayed_work jack_detect_work; + struct delayed_work button_press_work; + struct snd_soc_jack *jack; + int irq; + /* The lock protects the situation that an irq is generated + * while enabling or disabling or during an irq. + */ + struct mutex lock; + u8 mic1_src; + u8 mic2_src; + u8 jack_pol; + u8 interrupt_src; + u8 interrupt_clk; + bool jd_inverted; + unsigned int sysclk; +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0); + +static const char *const winsize[] = { + "0.25db/2 LRCK", + "0.25db/4 LRCK", + "0.25db/8 LRCK", + "0.25db/16 LRCK", + "0.25db/32 LRCK", + "0.25db/64 LRCK", + "0.25db/128 LRCK", + "0.25db/256 LRCK", + "0.25db/512 LRCK", + "0.25db/1024 LRCK", + "0.25db/2048 LRCK", + "0.25db/4096 LRCK", + "0.25db/8192 LRCK", + "0.25db/16384 LRCK", + "0.25db/32768 LRCK", + "0.25db/65536 LRCK", +}; + +static const char *const dacpol_txt[] = { + "Normal", "R Invert", "L Invert", "L + R Invert" }; + +static const struct soc_enum dacpol = + SOC_ENUM_SINGLE(ES8326_DAC_DSM, 4, 4, dacpol_txt); +static const struct soc_enum alc_winsize = + SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize); +static const struct soc_enum drc_winsize = + SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize); + +static const struct snd_kcontrol_new es8326_snd_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv), + SOC_ENUM("Playback Polarity", dacpol), + SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate), + SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv), + SOC_ENUM("DRC Winsize", drc_winsize), + SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE, 0, 0x0f, 0, drc_target_tlv), + + SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL, ES8326_ADC2_VOL, 0, 0xff, 0, + adc_vol_tlv), + SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE, 4, 0, 5, 0, adc_pga_tlv), + SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN, 0, 10, 0, adc_analog_pga_tlv), + SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE, 0, 0x0f, 0, softramp_rate), + SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0), + SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL, + 0, 4, 0, drc_recovery_tlv), + SOC_ENUM("ALC Capture Winsize", alc_winsize), + SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL, + 0, 0x0f, 0, drc_target_tlv), + +}; + +static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("MIC3"), + SND_SOC_DAPM_INPUT("MIC4"), + + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + /* Digital Interface */ + SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* ADC Digital Mute */ + SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0), + + /* Analog Power Supply*/ + SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1), + SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1), + SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0), + + SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), + + /* Headphone Charge Pump and Output */ + SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER, + 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER, + 2, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER, + 1, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER, + 0, 1, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, + ES8326_HPOR_SHIFT, 7, 7, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, + 0, 7, 7, 0), + + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_route es8326_dapm_routes[] = { + {"ADC L1", NULL, "MIC1"}, + {"ADC R1", NULL, "MIC2"}, + {"ADC L2", NULL, "MIC3"}, + {"ADC R2", NULL, "MIC4"}, + + {"ADC L", NULL, "ADC L1"}, + {"ADC R", NULL, "ADC R1"}, + {"ADC L", NULL, "ADC L2"}, + {"ADC R", NULL, "ADC R2"}, + + {"I2S OUT", NULL, "ADC L"}, + {"I2S OUT", NULL, "ADC R"}, + + {"I2S OUT", NULL, "Analog Power"}, + {"I2S OUT", NULL, "ADC Vref"}, + {"I2S OUT", NULL, "Vref Power"}, + {"I2S OUT", NULL, "IBias Power"}, + {"I2S IN", NULL, "Analog Power"}, + {"I2S IN", NULL, "DAC Vref"}, + {"I2S IN", NULL, "Vref Power"}, + {"I2S IN", NULL, "IBias Power"}, + + {"Right DAC", NULL, "I2S IN"}, + {"Left DAC", NULL, "I2S IN"}, + + {"LHPMIX", NULL, "Left DAC"}, + {"RHPMIX", NULL, "Right DAC"}, + + {"HPOR", NULL, "HPOR Cal"}, + {"HPOL", NULL, "HPOL Cal"}, + {"HPOR", NULL, "HPOR Supply"}, + {"HPOL", NULL, "HPOL Supply"}, + {"HPOL", NULL, "Headphone Charge Pump"}, + {"HPOR", NULL, "Headphone Charge Pump"}, + {"HPOL", NULL, "Headphone Driver Bias"}, + {"HPOR", NULL, "Headphone Driver Bias"}, + {"HPOL", NULL, "Headphone LDO"}, + {"HPOR", NULL, "Headphone LDO"}, + {"HPOL", NULL, "Headphone Reference"}, + {"HPOR", NULL, "Headphone Reference"}, + + {"HPOL", NULL, "LHPMIX"}, + {"HPOR", NULL, "RHPMIX"}, +}; + +static const struct regmap_range es8326_volatile_ranges[] = { + regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT), +}; + +static const struct regmap_access_table es8326_volatile_table = { + .yes_ranges = es8326_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), +}; + +static const struct regmap_config es8326_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .volatile_table = &es8326_volatile_table, + .cache_type = REGCACHE_RBTREE, +}; + +struct _coeff_div { + u16 fs; + u32 rate; + u32 mclk; + u8 reg4; + u8 reg5; + u8 reg6; + u8 reg7; + u8 reg8; + u8 reg9; + u8 rega; + u8 regb; +}; + +/* codec hifi mclk clock divider coefficients */ +/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */ +static const struct _coeff_div coeff_div[] = { + {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + + {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f}, + {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F}, + {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + + {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F}, + {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *codec = codec_dai->component; + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec); + + es8326->sysclk = freq; + + return 0; +} + +static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + u8 iface = 0; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFP: + snd_soc_component_update_bits(component, ES8326_RESET, + ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN); + break; + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + dev_err(component->dev, "Codec driver does not support right justified\n"); + return -EINVAL; + case SND_SOC_DAIFMT_LEFT_J: + iface |= ES8326_DAIFMT_LEFT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= ES8326_DAIFMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= ES8326_DAIFMT_DSP_B; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DAIFMT_MASK, iface); + + return 0; +} + +static int es8326_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + u8 srate = 0; + int coeff; + + coeff = get_coeff(es8326->sysclk, params_rate(params)); + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + srate |= ES8326_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + srate |= ES8326_S20_3_LE; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + srate |= ES8326_S18_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + srate |= ES8326_S24_LE; + break; + case SNDRV_PCM_FORMAT_S32_LE: + srate |= ES8326_S32_LE; + break; + default: + return -EINVAL; + } + + /* set iface & srate */ + snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DATA_LEN_MASK, srate); + + if (coeff >= 0) { + regmap_write(es8326->regmap, ES8326_CLK_DIV1, + coeff_div[coeff].reg4); + regmap_write(es8326->regmap, ES8326_CLK_DIV2, + coeff_div[coeff].reg5); + regmap_write(es8326->regmap, ES8326_CLK_DLL, + coeff_div[coeff].reg6); + regmap_write(es8326->regmap, ES8326_CLK_MUX, + coeff_div[coeff].reg7); + regmap_write(es8326->regmap, ES8326_CLK_ADC_SEL, + coeff_div[coeff].reg8); + regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, + coeff_div[coeff].reg9); + regmap_write(es8326->regmap, ES8326_CLK_ADC_OSR, + coeff_div[coeff].rega); + regmap_write(es8326->regmap, ES8326_CLK_DAC_OSR, + coeff_div[coeff].regb); + } else { + dev_warn(component->dev, "Clock coefficients do not match"); + } + + return 0; +} + +static int es8326_set_bias_level(struct snd_soc_component *codec, + enum snd_soc_bias_level level) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(es8326->mclk); + if (ret) + return ret; + regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02); + regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8326->mclk); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF); + regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_RESET, + ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); + break; + } + + return 0; +} + +#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops es8326_ops = { + .hw_params = es8326_pcm_hw_params, + .set_fmt = es8326_set_dai_fmt, + .set_sysclk = es8326_set_dai_sysclk, +}; + +static struct snd_soc_dai_driver es8326_dai = { + .name = "ES8326 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = es8326_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = es8326_FORMATS, + }, + .ops = &es8326_ops, + .symmetric_rate = 1, +}; + +static void es8326_enable_micbias(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void es8326_disable_micbias(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +/* + * For button detection, set the following in soundcard + * snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + * snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + * snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + */ +static void es8326_jack_button_handler(struct work_struct *work) +{ + struct es8326_priv *es8326 = + container_of(work, struct es8326_priv, button_press_work.work); + struct snd_soc_component *comp = es8326->component; + unsigned int iface; + static int button_to_report, press_count; + static int prev_button, cur_button; + + if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */ + return; + + mutex_lock(&es8326->lock); + iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + switch (iface) { + case 0x93: + /* pause button detected */ + cur_button = SND_JACK_BTN_0; + break; + case 0x6f: + /* button volume up */ + cur_button = SND_JACK_BTN_1; + break; + case 0x27: + /* button volume down */ + cur_button = SND_JACK_BTN_2; + break; + case 0x1e: + /* button released or not pressed */ + cur_button = 0; + break; + default: + break; + } + + if ((prev_button == cur_button) && (cur_button != 0)) { + press_count++; + if (press_count > 10) { + /* report a press every 500ms */ + snd_soc_jack_report(es8326->jack, cur_button, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + press_count = 0; + } + button_to_report = cur_button; + queue_delayed_work(system_wq, &es8326->button_press_work, + msecs_to_jiffies(50)); + } else if (prev_button != cur_button) { + /* mismatch, detect again */ + prev_button = cur_button; + queue_delayed_work(system_wq, &es8326->button_press_work, + msecs_to_jiffies(50)); + } else { + /* released or no pressed */ + if (button_to_report != 0) { + snd_soc_jack_report(es8326->jack, button_to_report, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + snd_soc_jack_report(es8326->jack, 0, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + button_to_report = 0; + } + } + mutex_unlock(&es8326->lock); +} + +static void es8326_jack_detect_handler(struct work_struct *work) +{ + struct es8326_priv *es8326 = + container_of(work, struct es8326_priv, jack_detect_work.work); + struct snd_soc_component *comp = es8326->component; + unsigned int iface; + + mutex_lock(&es8326->lock); + iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + dev_dbg(comp->dev, "gpio flag %#04x", iface); + if ((iface & ES8326_HPINSERT_FLAG) == 0) { + /* Jack unplugged or spurious IRQ */ + dev_dbg(comp->dev, "No headset detected"); + if (es8326->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); + snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src); + es8326_disable_micbias(comp); + } + } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) { + if (es8326->jack->status & SND_JACK_HEADSET) { + /* detect button */ + queue_delayed_work(system_wq, &es8326->button_press_work, 10); + } else { + if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) { + dev_dbg(comp->dev, "Headset detected"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADSET, SND_JACK_HEADSET); + snd_soc_component_write(comp, + ES8326_ADC1_SRC, es8326->mic1_src); + } else { + dev_dbg(comp->dev, "Headphone detected"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADPHONE, SND_JACK_HEADSET); + } + } + } + mutex_unlock(&es8326->lock); +} + +static irqreturn_t es8326_irq(int irq, void *dev_id) +{ + struct es8326_priv *es8326 = dev_id; + struct snd_soc_component *comp = es8326->component; + + if (!es8326->jack) + goto out; + + es8326_enable_micbias(comp); + + if (es8326->jack->status & SND_JACK_HEADSET) + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(10)); + else + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(300)); + +out: + return IRQ_HANDLED; +} + +static int es8326_resume(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int reg; + + regcache_cache_only(es8326->regmap, false); + regcache_sync(es8326->regmap); + + regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); + /* Two channel ADC */ + regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88); + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20); + regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + regmap_write(es8326->regmap, ES8326_HP_DET, + ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + snd_soc_component_update_bits(component, ES8326_PGAGAIN, + ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); + + regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); + if ((reg & ES8326_VERSION_B) == 1) { + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F); + /* enable button detect */ + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0); + } + + es8326_irq(es8326->irq, es8326); + return 0; +} + +static int es8326_suspend(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&es8326->jack_detect_work); + es8326_disable_micbias(component); + + regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF); + regcache_cache_only(es8326->regmap, true); + regcache_mark_dirty(es8326->regmap); + + return 0; +} + +static int es8326_probe(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + int ret; + + es8326->component = component; + es8326->jd_inverted = device_property_read_bool(component->dev, + "everest,jack-detect-inverted"); + + ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src); + if (ret != 0) { + dev_dbg(component->dev, "mic1-src return %d", ret); + es8326->mic1_src = ES8326_ADC_AMIC; + } + dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src); + + ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src); + if (ret != 0) { + dev_dbg(component->dev, "mic2-src return %d", ret); + es8326->mic2_src = ES8326_ADC_DMIC; + } + dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src); + + ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "jack-pol return %d", ret); + es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; + } + dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); + + ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "interrupt-src return %d", ret); + es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9; + } + dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src); + + ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "interrupt-clk return %d", ret); + es8326->interrupt_clk = 0x45; + } + dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk); + + es8326_resume(component); + return 0; +} + +static void es8326_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8326->lock); + if (es8326->jd_inverted) + snd_soc_component_update_bits(component, ES8326_HP_DET, + ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); + es8326->jack = jack; + + mutex_unlock(&es8326->lock); + es8326_irq(es8326->irq, es8326); +} + +static void es8326_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "Enter into %s\n", __func__); + if (!es8326->jack) + return; /* Already disabled (or never enabled) */ + cancel_delayed_work_sync(&es8326->jack_detect_work); + + mutex_lock(&es8326->lock); + if (es8326->jack->status & SND_JACK_MICROPHONE) { + es8326_disable_micbias(component); + snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); + } + es8326->jack = NULL; + mutex_unlock(&es8326->lock); +} + +static int es8326_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8326_enable_jack_detect(component, jack); + else + es8326_disable_jack_detect(component); + + return 0; +} + +static void es8326_remove(struct snd_soc_component *component) +{ + es8326_disable_jack_detect(component); + es8326_set_bias_level(component, SND_SOC_BIAS_OFF); +} + +static const struct snd_soc_component_driver soc_component_dev_es8326 = { + .probe = es8326_probe, + .remove = es8326_remove, + .resume = es8326_resume, + .suspend = es8326_suspend, + .set_bias_level = es8326_set_bias_level, + .set_jack = es8326_set_jack, + .dapm_widgets = es8326_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets), + .dapm_routes = es8326_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes), + .controls = es8326_snd_controls, + .num_controls = ARRAY_SIZE(es8326_snd_controls), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int es8326_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct es8326_priv *es8326; + int ret; + + es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL); + if (!es8326) + return -ENOMEM; + + i2c_set_clientdata(i2c, es8326); + es8326->i2c = i2c; + mutex_init(&es8326->lock); + es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config); + if (IS_ERR(es8326->regmap)) { + ret = PTR_ERR(es8326->regmap); + dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + es8326->irq = i2c->irq; + INIT_DELAYED_WORK(&es8326->jack_detect_work, + es8326_jack_detect_handler); + INIT_DELAYED_WORK(&es8326->button_press_work, + es8326_jack_button_handler); + /* ES8316 is level-based while ES8326 is edge-based */ + ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "es8326", es8326); + if (ret) { + dev_warn(&i2c->dev, "Failed to request IRQ: %d: %d\n", + es8326->irq, ret); + es8326->irq = -ENXIO; + } + + es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk"); + if (IS_ERR(es8326->mclk)) { + dev_err(&i2c->dev, "unable to get mclk\n"); + return PTR_ERR(es8326->mclk); + } + if (!es8326->mclk) + dev_warn(&i2c->dev, "assuming static mclk\n"); + + ret = clk_prepare_enable(es8326->mclk); + if (ret) { + dev_err(&i2c->dev, "unable to enable mclk\n"); + return ret; + } + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_es8326, + &es8326_dai, 1); +} + +static const struct i2c_device_id es8326_i2c_id[] = { + {"es8326", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, es8326_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id es8326_of_match[] = { + { .compatible = "everest,es8326", }, + {} +}; +MODULE_DEVICE_TABLE(of, es8326_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id es8326_acpi_match[] = { + {"ESSX8326", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, es8326_acpi_match); +#endif + +static struct i2c_driver es8326_i2c_driver = { + .driver = { + .name = "es8326", + .acpi_match_table = ACPI_PTR(es8326_acpi_match), + .of_match_table = of_match_ptr(es8326_of_match), + }, + .probe = es8326_i2c_probe, + .id_table = es8326_i2c_id, +}; +module_i2c_driver(es8326_i2c_driver); + +MODULE_DESCRIPTION("ASoC es8326 driver"); +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h new file mode 100755 index 000000000000..8e5ffe5ee10d --- /dev/null +++ b/sound/soc/codecs/es8326.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * es8326.h -- es8326 ALSA SoC audio driver + * Copyright Everest Semiconductor Co.,Ltd + * + * Authors: David Yang <yangxiaohua@everest-semi.com> + */ + +#ifndef _ES8326_H +#define _ES8326_H + +#define CONFIG_HHTECH_MINIPMP 1 + +/* ES8326 register space */ +#define ES8326_RESET 0x00 +#define ES8326_CLK_CTL 0x01 +#define ES8326_CLK_INV 0x02 +#define ES8326_CLK_RESAMPLE 0x03 +#define ES8326_CLK_DIV1 0x04 +#define ES8326_CLK_DIV2 0x05 +#define ES8326_CLK_DLL 0x06 +#define ES8326_CLK_MUX 0x07 +#define ES8326_CLK_ADC_SEL 0x08 +#define ES8326_CLK_DAC_SEL 0x09 +#define ES8326_CLK_ADC_OSR 0x0a +#define ES8326_CLK_DAC_OSR 0x0b +#define ES8326_CLK_DIV_CPC 0x0c +#define ES8326_CLK_DIV_BCLK 0x0d +#define ES8326_CLK_TRI 0x0e +#define ES8326_CLK_DIV_LRCK 0x0f +#define ES8326_CLK_VMIDS1 0x10 +#define ES8326_CLK_VMIDS2 0x11 +#define ES8326_CLK_CAL_TIME 0x12 +#define ES8326_FMT 0x13 + +#define ES8326_DAC_MUTE 0x14 +#define ES8326_ADC_MUTE 0x15 +#define ES8326_ANA_PDN 0x16 +#define ES8326_PGA_PDN 0x17 +#define ES8326_VMIDSEL 0x18 +#define ES8326_ANA_LP 0x19 +#define ES8326_ANA_DMS 0x1a +#define ES8326_ANA_MICBIAS 0x1b +#define ES8326_ANA_VSEL 0x1c +#define ES8326_SYS_BIAS 0x1d +#define ES8326_BIAS_SW1 0x1e +#define ES8326_BIAS_SW2 0x1f +#define ES8326_BIAS_SW3 0x20 +#define ES8326_BIAS_SW4 0x21 +#define ES8326_VMIDLOW 0x22 +#define ES8326_PGAGAIN 0x23 +#define ES8326_HP_DRIVER 0x24 +#define ES8326_DAC2HPMIX 0x25 +#define ES8326_HP_VOL 0x26 +#define ES8326_HP_CAL 0x27 +#define ES8326_HP_DRIVER_REF 0x28 +#define ES8326_ADC_SCALE 0x29 +#define ES8326_ADC1_SRC 0x2a +#define ES8326_ADC2_SRC 0x2b +#define ES8326_ADC1_VOL 0x2c +#define ES8326_ADC2_VOL 0x2d +#define ES8326_ADC_RAMPRATE 0x2e +#define ES8326_ALC_RECOVERY 0x32 +#define ES8326_ALC_LEVEL 0x33 +#define ES8326_ADC_HPFS1 0x34 +#define ES8326_ADC_HPFS2 0x35 +#define ES8326_ADC_EQ 0x36 +#define ES8326_HP_OFFSET_CAL 0x4A +#define ES8326_HPL_OFFSET_INI 0x4B +#define ES8326_HPR_OFFSET_INI 0x4C +#define ES8326_DAC_DSM 0x4D +#define ES8326_DAC_RAMPRATE 0x4E +#define ES8326_DAC_VPPSCALE 0x4F +#define ES8326_DAC_VOL 0x50 +#define ES8326_DRC_RECOVERY 0x53 +#define ES8326_DRC_WINSIZE 0x54 +#define ES8326_HPJACK_TIMER 0x56 +#define ES8326_HP_DET 0x57 +#define ES8326_INT_SOURCE 0x58 +#define ES8326_INTOUT_IO 0x59 +#define ES8326_SDINOUT1_IO 0x5A +#define ES8326_SDINOUT23_IO 0x5B +#define ES8326_JACK_PULSE 0x5C + +#define ES8326_PULLUP_CTL 0xF9 +#define ES8326_HP_DETECT 0xFB +#define ES8326_CHIP_ID1 0xFD +#define ES8326_CHIP_ID2 0xFE +#define ES8326_CHIP_VERSION 0xFF + +/* ES8326_RESET */ +#define ES8326_CSM_ON (1 << 7) +#define ES8326_MASTER_MODE_EN (1 << 6) +#define ES8326_PWRUP_SEQ_EN (1 << 5) +#define ES8326_CODEC_RESET (0x0f << 0) +#define ES8326_CSM_OFF (0 << 7) + +/* ES8326_CLK_CTL */ +#define ES8326_CLK_ON (0x7f << 0) +#define ES8326_CLK_OFF (0 << 0) + +/* ES8326_CLK_INV */ +#define ES8326_BCLK_AS_MCLK (1 << 3) + +/* ES8326_FMT */ +#define ES8326_S24_LE (0 << 2) +#define ES8326_S20_3_LE (1 << 2) +#define ES8326_S18_LE (2 << 2) +#define ES8326_S16_LE (3 << 2) +#define ES8326_S32_LE (4 << 2) +#define ES8326_DATA_LEN_MASK (7 << 2) + +#define ES8326_DAIFMT_MASK ((1 << 5) | (3 << 0)) +#define ES8326_DAIFMT_I2S 0 +#define ES8326_DAIFMT_LEFT_J (1 << 0) +#define ES8326_DAIFMT_DSP_A (3 << 0) +#define ES8326_DAIFMT_DSP_B ((1 << 5) | (3 << 0)) + +/* ES8326_PGAGAIN */ +#define ES8326_MIC_SEL_MASK (3 << 4) +#define ES8326_MIC1_SEL (1 << 4) +#define ES8326_MIC2_SEL (1 << 5) + +/* ES8326_HP_CAL */ +#define ES8326_HPOR_SHIFT 4 + +/* ES8326_ADC1_SRC */ +#define ES8326_ADC1_SHIFT 0 +#define ES8326_ADC2_SHIFT 4 +#define ES8326_ADC_SRC_ANA 0 +#define ES8326_ADC_SRC_ANA_INV_SW0 1 +#define ES8326_ADC_SRC_ANA_INV_SW1 2 +#define ES8326_ADC_SRC_DMIC_MCLK 3 +#define ES8326_ADC_SRC_DMIC_SDIN2 4 +#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5 +#define ES8326_ADC_SRC_DMIC_SDIN3 6 +#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7 + +#define ES8326_ADC_AMIC ((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \ + | (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT)) +#define ES8326_ADC_DMIC ((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \ + | (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT)) +/* ES8326_ADC2_SRC */ +#define ES8326_ADC3_SHIFT 0 +#define ES8326_ADC4_SHIFT 3 + +/* ES8326_HP_DET */ +#define ES8326_HP_DET_SRC_PIN27 (1 << 5) +#define ES8326_HP_DET_SRC_PIN9 (1 << 4) +#define ES8326_HP_DET_JACK_POL (1 << 3) +#define ES8326_HP_DET_BUTTON_POL (1 << 2) +#define ES8326_HP_TYPE_OMTP (3 << 0) +#define ES8326_HP_TYPE_CTIA (2 << 0) +#define ES8326_HP_TYPE_AUTO (1 << 0) +#define ES8326_HP_TYPE_AUTO_INV (0 << 0) + +/* ES8326_SDINOUT1_IO */ +#define ES8326_IO_INPUT (0 << 0) +#define ES8326_IO_SDIN_SLOT0 (1 << 0) +#define ES8326_IO_SDIN_SLOT1 (2 << 0) +#define ES8326_IO_SDIN_SLOT2 (3 << 0) +#define ES8326_IO_SDIN_SLOT7 (8 << 0) +#define ES8326_IO_DMIC_CLK (9 << 0) +#define ES8326_IO_DMIC_CLK_INV (0x0a << 0) +#define ES8326_IO_SDOUT2 (0x0b << 0) +#define ES8326_IO_LOW (0x0e << 0) +#define ES8326_IO_HIGH (0x0f << 0) +#define ES8326_ADC2DAC (1 << 3) +#define ES8326_SDINOUT1_SHIFT 4 + +/* ES8326_SDINOUT23_IO */ +#define ES8326_SDINOUT2_SHIFT 4 +#define ES8326_SDINOUT3_SHIFT 0 + +/* ES8326_HP_DETECT */ +#define ES8326_HPINSERT_FLAG (1 << 1) +#define ES8326_HPBUTTON_FLAG (1 << 0) + +/* ES8326_CHIP_VERSION 0xFF */ +#define ES8326_VERSION_B (1 << 0) + +#endif diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c index 6b0df0d750dc..68072e99fcc7 100644 --- a/sound/soc/codecs/es8328-i2c.c +++ b/sound/soc/codecs/es8328-i2c.c @@ -29,8 +29,7 @@ static const struct of_device_id es8328_of_match[] = { }; MODULE_DEVICE_TABLE(of, es8328_of_match); -static int es8328_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int es8328_i2c_probe(struct i2c_client *i2c) { return es8328_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &es8328_regmap_config)); @@ -41,7 +40,7 @@ static struct i2c_driver es8328_i2c_driver = { .name = "es8328", .of_match_table = es8328_of_match, }, - .probe = es8328_i2c_probe, + .probe_new = es8328_i2c_probe, .id_table = es8328_id, }; diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 9632afc2d4d6..160adc706cc6 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -84,7 +84,7 @@ struct es8328_priv { int mclkdiv2; const struct snd_pcm_hw_constraint_list *sysclk_constraints; const int *mclk_ratios; - bool master; + bool provider; struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; }; @@ -161,13 +161,16 @@ static int es8328_put_deemph(struct snd_kcontrol *kcontrol, if (deemph > 1) return -EINVAL; + if (es8328->deemph == deemph) + return 0; + ret = es8328_set_deemph(component); if (ret < 0) return ret; es8328->deemph = deemph; - return 0; + return 1; } @@ -462,7 +465,7 @@ static int es8328_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component); - if (es8328->master && es8328->sysclk_constraints) + if (es8328->provider && es8328->sysclk_constraints) snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, es8328->sysclk_constraints); @@ -486,7 +489,7 @@ static int es8328_hw_params(struct snd_pcm_substream *substream, else reg = ES8328_ADCCONTROL5; - if (es8328->master) { + if (es8328->provider) { if (!es8328->sysclk_constraints) { dev_err(component->dev, "No MCLK configured\n"); return -EINVAL; @@ -590,19 +593,19 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 dac_mode = 0; u8 adc_mode = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: /* Master serial port mode, with BCLK generated automatically */ snd_soc_component_update_bits(component, ES8328_MASTERMODE, ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC); - es8328->master = true; + es8328->provider = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: /* Slave serial port mode */ snd_soc_component_update_bits(component, ES8328_MASTERMODE, ES8328_MASTERMODE_MSC, 0); - es8328->master = false; + es8328->provider = false; break; default: return -EINVAL; @@ -841,7 +844,6 @@ static const struct snd_soc_component_driver es8328_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int es8328_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index e1235e695b0f..c6b1e77ffccd 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -73,7 +73,6 @@ static const struct snd_soc_component_driver soc_component_dev_gtm601 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int gtm601_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c new file mode 100644 index 000000000000..5371ff086261 --- /dev/null +++ b/sound/soc/codecs/hda-dai.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <sound/soc.h> +#include <sound/hda_codec.h> +#include "hda.h" + +static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + struct hda_pcm *pcm; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); + + dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n", + codec->core.vendor_id, stream_info, pcm, pcm->name, substream); + + snd_hda_codec_pcm_get(pcm); + + ret = stream_info->ops.open(stream_info, codec, substream); + if (ret < 0) { + dev_err(dai->dev, "codec open failed: %d\n", ret); + snd_hda_codec_pcm_put(pcm); + return ret; + } + + return 0; +} + +static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + struct hda_pcm *pcm; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); + + dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n", + codec->core.vendor_id, stream_info, pcm, pcm->name, substream); + + ret = stream_info->ops.close(stream_info, codec, substream); + if (ret < 0) + dev_err(dai->dev, "codec close failed: %d\n", ret); + + snd_hda_codec_pcm_put(pcm); +} + +static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct hda_pcm_stream *stream_info; + struct hda_codec *codec; + + codec = dev_to_hda_codec(dai->dev); + stream_info = snd_soc_dai_get_dma_data(dai, substream); + + snd_hda_codec_cleanup(codec, stream_info, substream); + + return 0; +} + +static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct hda_pcm_stream *stream_info; + struct hdac_stream *stream; + struct hda_codec *codec; + unsigned int format; + int ret; + + codec = dev_to_hda_codec(dai->dev); + stream = substream->runtime->private_data; + stream_info = snd_soc_dai_get_dma_data(dai, substream); + format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, + runtime->sample_bits, 0); + + ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream); + if (ret < 0) { + dev_err(dai->dev, "codec prepare failed: %d\n", ret); + return ret; + } + + return 0; +} + +const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = { + .startup = hda_codec_dai_startup, + .shutdown = hda_codec_dai_shutdown, + .hw_free = hda_codec_dai_hw_free, + .prepare = hda_codec_dai_prepare, +}; +EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops); diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c new file mode 100644 index 000000000000..61e8e9be6b8d --- /dev/null +++ b/sound/soc/codecs/hda.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> +#include <sound/hdaudio_ext.h> +#include <sound/hda_i915.h> +#include <sound/hda_codec.h> +#include "hda.h" + +static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count, + struct snd_soc_dai_driver **drivers) +{ + struct device *dev = &codec->core.dev; + struct snd_soc_dai_driver *drvs; + struct hda_pcm *pcm; + int i; + + drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL); + if (!drvs) + return -ENOMEM; + + pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); + + for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { + struct snd_soc_pcm_stream *stream; + int dir; + + dev_info(dev, "creating for %s %d\n", pcm->name, i); + drvs[i].id = i; + drvs[i].name = pcm->name; + drvs[i].ops = &snd_soc_hda_codec_dai_ops; + + dir = SNDRV_PCM_STREAM_PLAYBACK; + stream = &drvs[i].playback; + if (!pcm->stream[dir].substreams) { + dev_info(dev, "skipping playback dai for %s\n", pcm->name); + goto capture_dais; + } + + stream->stream_name = + devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + if (!stream->stream_name) + return -ENOMEM; + stream->channels_min = pcm->stream[dir].channels_min; + stream->channels_max = pcm->stream[dir].channels_max; + stream->rates = pcm->stream[dir].rates; + stream->formats = pcm->stream[dir].formats; + stream->sig_bits = pcm->stream[dir].maxbps; + +capture_dais: + dir = SNDRV_PCM_STREAM_CAPTURE; + stream = &drvs[i].capture; + if (!pcm->stream[dir].substreams) { + dev_info(dev, "skipping capture dai for %s\n", pcm->name); + continue; + } + + stream->stream_name = + devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name, + snd_pcm_direction_name(dir)); + if (!stream->stream_name) + return -ENOMEM; + stream->channels_min = pcm->stream[dir].channels_min; + stream->channels_max = pcm->stream[dir].channels_max; + stream->rates = pcm->stream[dir].rates; + stream->formats = pcm->stream[dir].formats; + stream->sig_bits = pcm->stream[dir].maxbps; + } + + *drivers = drvs; + return 0; +} + +static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component) +{ + struct snd_soc_dai_driver *drvs = NULL; + struct snd_soc_dapm_context *dapm; + struct hda_pcm *pcm; + int ret, pcm_count = 0; + + if (list_empty(&codec->pcm_list_head)) + return -EINVAL; + list_for_each_entry(pcm, &codec->pcm_list_head, list) + pcm_count++; + + ret = hda_codec_create_dais(codec, pcm_count, &drvs); + if (ret < 0) + return ret; + + dapm = snd_soc_component_get_dapm(component); + + list_for_each_entry(pcm, &codec->pcm_list_head, list) { + struct snd_soc_dai *dai; + + dai = snd_soc_register_dai(component, drvs, false); + if (!dai) { + dev_err(component->dev, "register dai for %s failed\n", pcm->name); + return -EINVAL; + } + + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret < 0) { + dev_err(component->dev, "create widgets failed: %d\n", ret); + snd_soc_unregister_dai(dai); + return ret; + } + + snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]); + drvs++; + } + + return 0; +} + +static void hda_codec_unregister_dais(struct hda_codec *codec, + struct snd_soc_component *component) +{ + struct snd_soc_dai *dai, *save; + struct hda_pcm *pcm; + + for_each_component_dais_safe(component, dai, save) { + list_for_each_entry(pcm, &codec->pcm_list_head, list) { + if (strcmp(dai->driver->name, pcm->name)) + continue; + + if (dai->playback_widget) + snd_soc_dapm_free_widget(dai->playback_widget); + if (dai->capture_widget) + snd_soc_dapm_free_widget(dai->capture_widget); + snd_soc_unregister_dai(dai); + break; + } + } +} + +int hda_codec_probe_complete(struct hda_codec *codec) +{ + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + int ret; + + ret = snd_hda_codec_build_controls(codec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", ret); + goto out; + } + + /* Bus suspended codecs as it does not manage their pm */ + pm_runtime_set_active(&hdev->dev); + /* rpm was forbidden in snd_hda_codec_device_new() */ + snd_hda_codec_set_power_save(codec, 2000); + snd_hda_codec_register(codec); +out: + /* Complement pm_runtime_get_sync(bus) in probe */ + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(hda_codec_probe_complete); + +/* Expects codec with usage_count=1 and status=suspended */ +static int hda_codec_probe(struct snd_soc_component *component) +{ + struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + struct hdac_ext_link *hlink; + hda_codec_patch_t patch; + int ret; + +#ifdef CONFIG_PM + WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 || + !pm_runtime_status_suspended(&hdev->dev)); +#endif + + hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + + pm_runtime_get_sync(bus->dev); + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, true); + snd_hdac_ext_bus_link_get(bus, hlink); + + ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec, + false); + if (ret < 0) { + dev_err(&hdev->dev, "create hda codec failed: %d\n", ret); + goto device_new_err; + } + + ret = snd_hda_codec_set_name(codec, codec->preset->name); + if (ret < 0) { + dev_err(&hdev->dev, "name failed %s\n", codec->preset->name); + goto err; + } + + ret = snd_hdac_regmap_init(&codec->core); + if (ret < 0) { + dev_err(&hdev->dev, "regmap init failed\n"); + goto err; + } + + patch = (hda_codec_patch_t)codec->preset->driver_data; + if (!patch) { + dev_err(&hdev->dev, "no patch specified?\n"); + ret = -EINVAL; + goto err; + } + + ret = patch(codec); + if (ret < 0) { + dev_err(&hdev->dev, "patch failed %d\n", ret); + goto err; + } + + ret = snd_hda_codec_parse_pcms(codec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + goto parse_pcms_err; + } + + ret = hda_codec_register_dais(codec, component); + if (ret < 0) { + dev_err(&hdev->dev, "update dais failed: %d\n", ret); + goto parse_pcms_err; + } + + if (!hda_codec_is_display(codec)) { + ret = hda_codec_probe_complete(codec); + if (ret < 0) + goto complete_err; + } + + codec->core.lazy_cache = true; + + return 0; + +complete_err: + hda_codec_unregister_dais(codec, component); +parse_pcms_err: + if (codec->patch_ops.free) + codec->patch_ops.free(codec); +err: + snd_hda_codec_cleanup_for_unbind(codec); +device_new_err: + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, false); + + snd_hdac_ext_bus_link_put(bus, hlink); + + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + return ret; +} + +/* Leaves codec with usage_count=1 and status=suspended */ +static void hda_codec_remove(struct snd_soc_component *component) +{ + struct hda_codec *codec = dev_to_hda_codec(component->dev); + struct hdac_device *hdev = &codec->core; + struct hdac_bus *bus = hdev->bus; + struct hdac_ext_link *hlink; + bool was_registered = codec->core.registered; + + /* Don't allow any more runtime suspends */ + pm_runtime_forbid(&hdev->dev); + + hda_codec_unregister_dais(codec, component); + + if (codec->patch_ops.free) + codec->patch_ops.free(codec); + + snd_hda_codec_cleanup_for_unbind(codec); + pm_runtime_put_noidle(&hdev->dev); + /* snd_hdac_device_exit() is only called on bus remove */ + pm_runtime_set_suspended(&hdev->dev); + + if (hda_codec_is_display(codec)) + snd_hdac_display_power(bus, hdev->addr, false); + + hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr); + if (hlink) + snd_hdac_ext_bus_link_put(bus, hlink); + /* + * HDMI card's hda_codec_probe_complete() (see late_probe()) may + * not be called due to early error, leaving bus uc unbalanced + */ + if (!was_registered) { + pm_runtime_mark_last_busy(bus->dev); + pm_runtime_put_autosuspend(bus->dev); + } + +#ifdef CONFIG_PM + WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 || + !pm_runtime_status_suspended(&hdev->dev)); +#endif +} + +static const struct snd_soc_dapm_route hda_dapm_routes[] = { + {"AIF1TX", NULL, "Codec Input Pin1"}, + {"AIF2TX", NULL, "Codec Input Pin2"}, + {"AIF3TX", NULL, "Codec Input Pin3"}, + + {"Codec Output Pin1", NULL, "AIF1RX"}, + {"Codec Output Pin2", NULL, "AIF2RX"}, + {"Codec Output Pin3", NULL, "AIF3RX"}, +}; + +static const struct snd_soc_dapm_widget hda_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Input Pins */ + SND_SOC_DAPM_INPUT("Codec Input Pin1"), + SND_SOC_DAPM_INPUT("Codec Input Pin2"), + SND_SOC_DAPM_INPUT("Codec Input Pin3"), + + /* Output Pins */ + SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), +}; + +static struct snd_soc_dai_driver card_binder_dai = { + .id = -1, + .name = "codec-probing-DAI", +}; + +static int hda_hdev_attach(struct hdac_device *hdev) +{ + struct hda_codec *codec = dev_to_hda_codec(&hdev->dev); + struct snd_soc_component_driver *comp_drv; + + comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL); + if (!comp_drv) + return -ENOMEM; + + /* + * It's save to rely on dev_name() rather than a copy as component + * driver's lifetime is directly tied to hda codec one + */ + comp_drv->name = dev_name(&hdev->dev); + comp_drv->probe = hda_codec_probe; + comp_drv->remove = hda_codec_remove; + comp_drv->idle_bias_on = false; + if (!hda_codec_is_display(codec)) { + comp_drv->dapm_widgets = hda_dapm_widgets; + comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets); + comp_drv->dapm_routes = hda_dapm_routes; + comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes); + } + + return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1); +} + +static int hda_hdev_detach(struct hdac_device *hdev) +{ + struct hda_codec *codec = dev_to_hda_codec(&hdev->dev); + + if (codec->core.registered) + cancel_delayed_work_sync(&codec->jackpoll_work); + + snd_soc_unregister_component(&hdev->dev); + + return 0; +} + +const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = { + .hdev_attach = hda_hdev_attach, + .hdev_detach = hda_hdev_detach, +}; +EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops); + +MODULE_DESCRIPTION("HD-Audio codec driver"); +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h new file mode 100644 index 000000000000..78a2be4945b1 --- /dev/null +++ b/sound/soc/codecs/hda.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * + * Author: Cezary Rojewski <cezary.rojewski@intel.com> + */ + +#ifndef SND_SOC_CODECS_HDA_H +#define SND_SOC_CODECS_HDA_H + +#define hda_codec_is_display(codec) \ + ((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086) + +extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops; + +extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops; +int hda_codec_probe_complete(struct hda_codec *codec); + +#endif diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 390dd6c7f6a5..8af434e14bfb 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -46,9 +46,8 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); -static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width); +static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, void *stream, + int direction); static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai); @@ -58,7 +57,7 @@ static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .prepare = hdac_hda_dai_prepare, .hw_params = hdac_hda_dai_hw_params, .hw_free = hdac_hda_dai_hw_free, - .set_tdm_slot = hdac_hda_dai_set_tdm_slot, + .set_stream = hdac_hda_dai_set_stream, }; static struct snd_soc_dai_driver hdac_hda_dais[] = { @@ -180,21 +179,22 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = { }; -static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width) +static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, + void *stream, int direction) { struct snd_soc_component *component = dai->component; struct hdac_hda_priv *hda_pvt; struct hdac_hda_pcm *pcm; + struct hdac_stream *hstream; + + if (!stream) + return -EINVAL; hda_pvt = snd_soc_component_get_drvdata(component); pcm = &hda_pvt->pcm[dai->id]; + hstream = (struct hdac_stream *)stream; - if (tx_mask) - pcm->stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; - else - pcm->stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + pcm->stream_tag[direction] = hstream->stream_tag; return 0; } @@ -246,7 +246,7 @@ static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, return -EINVAL; hda_stream = &pcm->stream[substream->stream]; - snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream); + snd_hda_codec_cleanup(hda_pvt->codec, hda_stream, substream); return 0; } @@ -264,7 +264,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, int ret = 0; hda_pvt = snd_soc_component_get_drvdata(component); - hdev = &hda_pvt->codec.core; + hdev = &hda_pvt->codec->core; pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); if (!pcm) return -EINVAL; @@ -274,7 +274,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; format_val = hda_pvt->pcm[dai->id].format_val[substream->stream]; - ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, + ret = snd_hda_codec_prepare(hda_pvt->codec, hda_stream, stream, format_val, substream); if (ret < 0) dev_err(&hdev->dev, "codec prepare failed %d\n", ret); @@ -299,7 +299,7 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - return hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream); + return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream); } static void hdac_hda_dai_close(struct snd_pcm_substream *substream, @@ -317,7 +317,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream); + hda_stream->ops.close(hda_stream, hda_pvt->codec, substream); snd_hda_codec_pcm_put(pcm); } @@ -325,7 +325,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai) { - struct hda_codec *hcodec = &hda_pvt->codec; + struct hda_codec *hcodec = hda_pvt->codec; struct hda_pcm *cpcm; const char *pcm_name; @@ -363,8 +363,13 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, } list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { - if (strstr(cpcm->name, pcm_name)) + if (strstr(cpcm->name, pcm_name)) { + if (strcmp(pcm_name, "Analog") == 0) { + if (strstr(cpcm->name, "Alt Analog")) + continue; + } return cpcm; + } } dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name); @@ -389,8 +394,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct hdac_device *hdev = &hda_pvt->codec.core; - struct hda_codec *hcodec = &hda_pvt->codec; + struct hdac_device *hdev = &hda_pvt->codec->core; + struct hda_codec *hcodec = hda_pvt->codec; struct hdac_ext_link *hlink; hda_codec_patch_t patch; int ret; @@ -413,7 +418,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) HDA_CODEC_IDX_CONTROLLER, true); ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, - hdev->addr, hcodec); + hdev->addr, hcodec, true); if (ret < 0) { dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); goto error_no_pm; @@ -456,9 +461,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_dbg(&hdev->dev, "no patch file found\n"); } - /* configure codec for 1:1 PCM:DAI mapping */ - hcodec->mst_no_extra_pcms = 1; - ret = snd_hda_codec_parse_pcms(hcodec); if (ret < 0) { dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); @@ -510,8 +512,8 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) { struct hdac_hda_priv *hda_pvt = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = &hda_pvt->codec.core; - struct hda_codec *codec = &hda_pvt->codec; + struct hdac_device *hdev = &hda_pvt->codec->core; + struct hda_codec *codec = hda_pvt->codec; struct hdac_ext_link *hlink = NULL; hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); @@ -566,19 +568,19 @@ static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { }; static const struct snd_soc_component_driver hdac_hda_codec = { - .probe = hdac_hda_codec_probe, - .remove = hdac_hda_codec_remove, - .idle_bias_on = false, - .dapm_widgets = hdac_hda_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), - .dapm_routes = hdac_hda_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), + .probe = hdac_hda_codec_probe, + .remove = hdac_hda_codec_remove, + .dapm_widgets = hdac_hda_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), + .dapm_routes = hdac_hda_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), + .idle_bias_on = false, + .endianness = 1, }; static int hdac_hda_dev_probe(struct hdac_device *hdev) { struct hdac_ext_link *hlink; - struct hdac_hda_priv *hda_pvt; int ret; /* hold the ref while we probe */ @@ -589,10 +591,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) } snd_hdac_ext_bus_link_get(hdev->bus, hlink); - hda_pvt = hdac_to_hda_priv(hdev); - if (!hda_pvt) - return -ENOMEM; - /* ASoC specific initialization */ ret = devm_snd_soc_register_component(&hdev->dev, &hdac_hda_codec, hdac_hda_dais, @@ -602,7 +600,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) return ret; } - dev_set_drvdata(&hdev->dev, hda_pvt); snd_hdac_ext_bus_link_put(hdev->bus, hlink); return ret; diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index d0efc5e254ae..fc19c34ca00e 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -23,7 +23,7 @@ struct hdac_hda_pcm { }; struct hdac_hda_priv { - struct hda_codec codec; + struct hda_codec *codec; struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID]; bool need_display_power; }; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 66408a98298b..cb23650ad522 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2058,7 +2058,6 @@ static const struct snd_soc_component_driver hdmi_hda_codec = { .remove = hdmi_codec_remove, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b61f980cabdc..0b1cdb2d6049 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -20,10 +20,6 @@ #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 -struct hdmi_codec_channel_map_table { - unsigned char map; /* ALSA API channel map position */ -}; - /* * CEA speaker placement for HDMI 1.4: * @@ -277,7 +273,7 @@ struct hdmi_codec_priv { bool busy; struct snd_soc_jack *jack; unsigned int jack_status; - u8 iec_status[5]; + u8 iec_status[AES_IEC958_STATUS_SIZE]; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -606,18 +602,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, /* Reset daifmt */ memset(cf, 0, sizeof(*cf)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf->bit_clk_master = 1; - cf->frame_clk_master = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cf->bit_clk_provider = 1; + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: - cf->frame_clk_master = 1; + case SND_SOC_DAIFMT_CBC_CFP: + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: - cf->bit_clk_master = 1; + case SND_SOC_DAIFMT_CBP_CFC: + cf->bit_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -727,10 +723,8 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) -#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) /* * This list is only for formats allowed on the I2S bus. So there is @@ -740,12 +734,9 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { * problems, we should add the video side driver an option to disable * them. */ -#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) +#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) static struct snd_kcontrol_new hdmi_codec_controls[] = { { @@ -832,7 +823,7 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); + daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL); if (!daifmt) return -ENOMEM; @@ -899,17 +890,10 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } -static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) -{ - kfree(dai->playback_dma_data); - return 0; -} - static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, .probe = hdmi_dai_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -934,7 +918,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, .probe = hdmi_dai_spdif_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -982,7 +965,6 @@ static const struct snd_soc_component_driver hdmi_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, .set_jack = hdmi_codec_set_jack, }; diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index de4c8460ab3d..58a382254718 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -41,7 +41,6 @@ static const struct snd_soc_component_driver ics43432_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int ics43432_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index e05c4f27486e..8222cde6e3b9 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -200,12 +200,12 @@ static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(component->dev, "rk3036_codec dai set fmt : %08x\n", fmt); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: reg01_val |= INNO_R01_PINDIR_IN_SLAVE | INNO_R01_I2SMODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: reg01_val |= INNO_R01_PINDIR_OUT_MASTER | INNO_R01_I2SMODE_MASTER; break; @@ -387,7 +387,6 @@ static const struct snd_soc_component_driver rk3036_codec_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rk3036_codec_regmap_config = { diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 79afced75d76..50105d72b2b7 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -973,11 +973,11 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct snd_soc_component *component = codec_dai->component; unsigned int aif_val = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: aif_val &= ~ISABELLE_AIF_MS; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif_val |= ISABELLE_AIF_MS; break; default: @@ -1095,7 +1095,6 @@ static const struct snd_soc_component_driver soc_component_dev_isabelle = { .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config isabelle_regmap_config = { @@ -1108,8 +1107,7 @@ static const struct regmap_config isabelle_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int isabelle_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int isabelle_i2c_probe(struct i2c_client *i2c) { struct regmap *isabelle_regmap; int ret = 0; @@ -1144,7 +1142,7 @@ static struct i2c_driver isabelle_i2c_driver = { .driver = { .name = "isabelle", }, - .probe = isabelle_i2c_probe, + .probe_new = isabelle_i2c_probe, .id_table = isabelle_i2c_id, }; diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 5201a8f6d7b6..71ea576f7e67 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -136,14 +136,17 @@ enum { #define REG_CGR3_GO1L_OFFSET 0 #define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET) +#define REG_CGR10_GIL_OFFSET 0 +#define REG_CGR10_GIR_OFFSET 4 + struct jz_icdc { struct regmap *regmap; void __iomem *base; struct clk *clk; }; -static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0); -static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0); static const struct snd_kcontrol_new jz4725b_codec_controls[] = { SOC_DOUBLE_TLV("Master Playback Volume", @@ -151,11 +154,11 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = { REG_CGR1_GODL_OFFSET, REG_CGR1_GODR_OFFSET, 0xf, 1, jz4725b_dac_tlv), - SOC_DOUBLE_R_TLV("Master Capture Volume", - JZ4725B_CODEC_REG_CGR3, - JZ4725B_CODEC_REG_CGR2, - REG_CGR2_GO1R_OFFSET, - 0x1f, 1, jz4725b_line_tlv), + SOC_DOUBLE_TLV("Master Capture Volume", + JZ4725B_CODEC_REG_CGR10, + REG_CGR10_GIL_OFFSET, + REG_CGR10_GIR_OFFSET, + 0xf, 0, jz4725b_adc_tlv), SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, REG_CR1_DAC_MUTE_OFFSET, 1, 1), @@ -180,7 +183,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, jz4725b_codec_adc_src_texts, jz4725b_codec_adc_src_values); static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = - SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum); + SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum); static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1, @@ -225,7 +228,7 @@ static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADC", "Capture", JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1), - SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_MUX("ADC Source Capture Route", SND_SOC_NOPM, 0, 0, &jz4725b_codec_adc_src_ctrl), /* Mixer */ @@ -236,7 +239,8 @@ static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = { SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1, REG_CR1_DACSEL_OFFSET, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Line In", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_LIN_OFFSET, 1, NULL, 0), SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1, REG_CR1_HP_DIS_OFFSET, 1, NULL, 0), @@ -283,11 +287,11 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = { {"Mixer", NULL, "DAC to Mixer"}, {"Mixer to ADC", NULL, "Mixer"}, - {"ADC Source", "Mixer", "Mixer to ADC"}, - {"ADC Source", "Line In", "Line In"}, - {"ADC Source", "Mic 1", "Mic 1"}, - {"ADC Source", "Mic 2", "Mic 2"}, - {"ADC", NULL, "ADC Source"}, + {"ADC Source Capture Route", "Mixer", "Mixer to ADC"}, + {"ADC Source Capture Route", "Line In", "Line In"}, + {"ADC Source Capture Route", "Mic 1", "Mic 1"}, + {"ADC Source Capture Route", "Mic 2", "Mic 2"}, + {"ADC", NULL, "ADC Source Capture Route"}, {"Out Stage", NULL, "Mixer"}, {"HP Out", NULL, "Out Stage"}, diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 081485f784e9..7c25acf6ff0d 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -291,8 +291,6 @@ static const struct snd_soc_component_driver soc_codec_dev_jz4740_codec = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static const struct regmap_config jz4740_codec_regmap_config = { diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 6b60120f59a6..1d0c467ab57b 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -307,6 +307,7 @@ static const DECLARE_TLV_DB_MINMAX_MUTE(dac_tlv, -3100, 0); static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0); static const DECLARE_TLV_DB_MINMAX(out_tlv, -2500, 600); static const DECLARE_TLV_DB_SCALE(linein_tlv, -2500, 100, 0); +static const DECLARE_TLV_DB_MINMAX(mixer_tlv, -3100, 0); /* Unconditional controls. */ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = { @@ -319,6 +320,14 @@ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = { SOC_DOUBLE_R_TLV("Line In Bypass Playback Volume", JZ4770_CODEC_REG_GCR_LIBYL, JZ4770_CODEC_REG_GCR_LIBYR, REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, linein_tlv), + + SOC_SINGLE_TLV("Mixer Capture Volume", + JZ4770_CODEC_REG_GCR_MIXADC, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, mixer_tlv), + + SOC_SINGLE_TLV("Mixer Playback Volume", + JZ4770_CODEC_REG_GCR_MIXDAC, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, mixer_tlv), }; static const struct snd_kcontrol_new jz4770_codec_pcm_playback_controls[] = { diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 300b325e2fdd..dba161305de8 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -115,8 +115,7 @@ static const struct regmap_config lm4857_regmap_config = { .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), }; -static int lm4857_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm4857_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -138,7 +137,7 @@ static struct i2c_driver lm4857_i2c_driver = { .driver = { .name = "lm4857", }, - .probe = lm4857_i2c_probe, + .probe_new = lm4857_i2c_probe, .id_table = lm4857_i2c_id, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index fb0fb23537e7..a2e782cc4276 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1146,17 +1146,17 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) int clk_phase = 0; int clk_shift = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: aif_val = 0; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS | LM49453_AUDIO_PORT1_BASIC_SYNC_MS; break; @@ -1399,7 +1399,6 @@ static const struct snd_soc_component_driver soc_component_dev_lm49453 = { .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config lm49453_regmap_config = { @@ -1412,8 +1411,7 @@ static const struct regmap_config lm49453_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int lm49453_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int lm49453_i2c_probe(struct i2c_client *i2c) { struct lm49453_priv *lm49453; int ret = 0; @@ -1443,11 +1441,6 @@ static int lm49453_i2c_probe(struct i2c_client *i2c, return ret; } -static int lm49453_i2c_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id lm49453_i2c_id[] = { { "lm49453", 0 }, { } @@ -1458,8 +1451,7 @@ static struct i2c_driver lm49453_i2c_driver = { .driver = { .name = "lm49453", }, - .probe = lm49453_i2c_probe, - .remove = lm49453_i2c_remove, + .probe_new = lm49453_i2c_probe, .id_table = lm49453_i2c_id, }; diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c index 54426a90bc0b..13fbd8830b09 100644 --- a/sound/soc/codecs/lochnagar-sc.c +++ b/sound/soc/codecs/lochnagar-sc.c @@ -212,12 +212,12 @@ static struct snd_soc_dai_driver lochnagar_sc_dai[] = { }; static const struct snd_soc_component_driver lochnagar_sc_driver = { - .non_legacy_dai_naming = 1, - .dapm_widgets = lochnagar_sc_widgets, .num_dapm_widgets = ARRAY_SIZE(lochnagar_sc_widgets), .dapm_routes = lochnagar_sc_routes, .num_dapm_routes = ARRAY_SIZE(lochnagar_sc_routes), + + .endianness = 1, }; static int lochnagar_sc_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c new file mode 100644 index 000000000000..1b9082d237c1 --- /dev/null +++ b/sound/soc/codecs/lpass-macro-common.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2022, The Linux Foundation. All rights reserved. + +#include <linux/export.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> + +#include "lpass-macro-common.h" + +struct lpass_macro *lpass_macro_pds_init(struct device *dev) +{ + struct lpass_macro *l_pds; + int ret; + + if (!of_find_property(dev->of_node, "power-domains", NULL)) + return NULL; + + l_pds = devm_kzalloc(dev, sizeof(*l_pds), GFP_KERNEL); + if (!l_pds) + return ERR_PTR(-ENOMEM); + + l_pds->macro_pd = dev_pm_domain_attach_by_name(dev, "macro"); + if (IS_ERR_OR_NULL(l_pds->macro_pd)) { + ret = l_pds->macro_pd ? PTR_ERR(l_pds->macro_pd) : -ENODATA; + goto macro_err; + } + + ret = pm_runtime_resume_and_get(l_pds->macro_pd); + if (ret < 0) + goto macro_sync_err; + + l_pds->dcodec_pd = dev_pm_domain_attach_by_name(dev, "dcodec"); + if (IS_ERR_OR_NULL(l_pds->dcodec_pd)) { + ret = l_pds->dcodec_pd ? PTR_ERR(l_pds->dcodec_pd) : -ENODATA; + goto dcodec_err; + } + + ret = pm_runtime_resume_and_get(l_pds->dcodec_pd); + if (ret < 0) + goto dcodec_sync_err; + return l_pds; + +dcodec_sync_err: + dev_pm_domain_detach(l_pds->dcodec_pd, false); +dcodec_err: + pm_runtime_put(l_pds->macro_pd); +macro_sync_err: + dev_pm_domain_detach(l_pds->macro_pd, false); +macro_err: + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(lpass_macro_pds_init); + +void lpass_macro_pds_exit(struct lpass_macro *pds) +{ + if (pds) { + pm_runtime_put(pds->macro_pd); + dev_pm_domain_detach(pds->macro_pd, false); + pm_runtime_put(pds->dcodec_pd); + dev_pm_domain_detach(pds->dcodec_pd, false); + } +} +EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); + +MODULE_DESCRIPTION("Common macro driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h new file mode 100644 index 000000000000..f2cbf9fe2c6e --- /dev/null +++ b/sound/soc/codecs/lpass-macro-common.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + */ + +#ifndef __LPASS_MACRO_COMMON_H__ +#define __LPASS_MACRO_COMMON_H__ + +struct lpass_macro { + struct device *macro_pd; + struct device *dcodec_pd; +}; + +struct lpass_macro *lpass_macro_pds_init(struct device *dev); +void lpass_macro_pds_exit(struct lpass_macro *pds); + +#endif /* __LPASS_MACRO_COMMON_H__ */ diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index aec5127260fd..a9ef9d5ffcc5 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/clk.h> #include <sound/soc.h> #include <sound/pcm.h> @@ -14,6 +15,8 @@ #include <linux/of_clk.h> #include <linux/clk-provider.h> +#include "lpass-macro-common.h" + #define CDC_RX_TOP_TOP_CFG0 (0x0000) #define CDC_RX_TOP_SWR_CTRL (0x0008) #define CDC_RX_TOP_DEBUG (0x000C) @@ -593,7 +596,6 @@ struct rx_macro { int rx_port_value[RX_MACRO_PORTS_MAX]; u16 prim_int_users[INTERP_MAX]; int rx_mclk_users; - bool reset_swr; int clsh_users; int rx_mclk_cnt; bool is_ear_mode_on; @@ -606,9 +608,13 @@ struct rx_macro { int is_softclip_on; int is_aux_hpf_on; int softclip_clk_users; - + struct lpass_macro *pds; struct regmap *regmap; - struct clk_bulk_data clks[RX_NUM_CLKS_MAX]; + struct clk *mclk; + struct clk *npl; + struct clk *macro; + struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; }; #define to_rx_macro(_hw) container_of(_hw, struct rx_macro, hw) @@ -2039,6 +2045,10 @@ static int rx_macro_load_compander_coeff(struct snd_soc_component *component, int i; int hph_pwr_mode; + /* AUX does not have compander */ + if (comp == INTERP_AUX) + return 0; + if (!rx->comp_enabled[comp]) return 0; @@ -2268,7 +2278,7 @@ static int rx_macro_mux_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm); struct rx_macro *rx = snd_soc_component_get_drvdata(component); - ucontrol->value.integer.value[0] = + ucontrol->value.enumerated.item[0] = rx->rx_port_value[widget->shift]; return 0; } @@ -2280,7 +2290,7 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; - u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 rx_port_value = ucontrol->value.enumerated.item[0]; u32 aif_rst; struct rx_macro *rx = snd_soc_component_get_drvdata(component); @@ -2392,7 +2402,7 @@ static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct rx_macro *rx = snd_soc_component_get_drvdata(component); - ucontrol->value.integer.value[0] = rx->hph_pwr_mode; + ucontrol->value.enumerated.item[0] = rx->hph_pwr_mode; return 0; } @@ -2402,7 +2412,7 @@ static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct rx_macro *rx = snd_soc_component_get_drvdata(component); - rx->hph_pwr_mode = ucontrol->value.integer.value[0]; + rx->hph_pwr_mode = ucontrol->value.enumerated.item[0]; return 0; } @@ -2688,8 +2698,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component, int reg, b2_reg; /* Address does not automatically update if reading */ - reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx; - b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx; + reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx; + b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx; snd_soc_component_write(component, reg, ((band_idx * BAND_MAX + coeff_idx) * @@ -2718,7 +2728,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component, static void set_iir_band_coeff(struct snd_soc_component *component, int iir_idx, int band_idx, uint32_t value) { - int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx; + int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx; snd_soc_component_write(component, reg, (value & 0xFF)); snd_soc_component_write(component, reg, (value >> 8) & 0xFF); @@ -2739,7 +2749,7 @@ static int rx_macro_put_iir_band_audio_mixer( int iir_idx = ctl->iir_idx; int band_idx = ctl->band_idx; u32 coeff[BAND_MAX]; - int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx; + int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx; memcpy(&coeff[0], ucontrol->value.bytes.data, params->max); @@ -3422,20 +3432,24 @@ static int rx_macro_component_probe(struct snd_soc_component *component) static int swclk_gate_enable(struct clk_hw *hw) { struct rx_macro *rx = to_rx_macro(hw); + int ret; + + ret = clk_prepare_enable(rx->mclk); + if (ret) { + dev_err(rx->dev, "unable to prepare mclk\n"); + return ret; + } rx_macro_mclk_enable(rx, true); - if (rx->reset_swr) - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, - CDC_RX_SWR_RESET_MASK, - CDC_RX_SWR_RESET); + regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + CDC_RX_SWR_RESET_MASK, + CDC_RX_SWR_RESET); regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, CDC_RX_SWR_CLK_EN_MASK, 1); - if (rx->reset_swr) - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, - CDC_RX_SWR_RESET_MASK, 0); - rx->reset_swr = false; + regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + CDC_RX_SWR_RESET_MASK, 0); return 0; } @@ -3448,6 +3462,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_RX_SWR_CLK_EN_MASK, 0); rx_macro_mclk_enable(rx, false); + clk_disable_unprepare(rx->mclk); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -3475,17 +3490,16 @@ static const struct clk_ops swclk_gate_ops = { }; -static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx) +static int rx_macro_register_mclk_output(struct rx_macro *rx) { struct device *dev = rx->dev; - struct device_node *np = dev->of_node; const char *parent_clk_name = NULL; const char *clk_name = "lpass-rx-mclk"; struct clk_hw *hw; struct clk_init_data init; int ret; - parent_clk_name = __clk_get_name(rx->clks[2].clk); + parent_clk_name = __clk_get_name(rx->npl); init.name = clk_name; init.ops = &swclk_gate_ops; @@ -3494,13 +3508,11 @@ static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx) init.num_parents = 1; rx->hw.init = &init; hw = &rx->hw; - ret = clk_hw_register(rx->dev, hw); + ret = devm_clk_hw_register(rx->dev, hw); if (ret) - return ERR_PTR(ret); - - of_clk_add_provider(np, of_clk_src_simple_get, hw->clk); + return ret; - return NULL; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); } static const struct snd_soc_component_driver rx_macro_component_drv = { @@ -3525,44 +3537,101 @@ static int rx_macro_probe(struct platform_device *pdev) if (!rx) return -ENOMEM; - rx->clks[0].id = "macro"; - rx->clks[1].id = "dcodec"; - rx->clks[2].id = "mclk"; - rx->clks[3].id = "npl"; - rx->clks[4].id = "fsgen"; + rx->macro = devm_clk_get_optional(dev, "macro"); + if (IS_ERR(rx->macro)) + return PTR_ERR(rx->macro); - ret = devm_clk_bulk_get_optional(dev, RX_NUM_CLKS_MAX, rx->clks); - if (ret) { - dev_err(dev, "Error getting RX Clocks (%d)\n", ret); - return ret; - } + rx->dcodec = devm_clk_get_optional(dev, "dcodec"); + if (IS_ERR(rx->dcodec)) + return PTR_ERR(rx->dcodec); + + rx->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(rx->mclk)) + return PTR_ERR(rx->mclk); + + rx->npl = devm_clk_get(dev, "npl"); + if (IS_ERR(rx->npl)) + return PTR_ERR(rx->npl); + + rx->fsgen = devm_clk_get(dev, "fsgen"); + if (IS_ERR(rx->fsgen)) + return PTR_ERR(rx->fsgen); + + rx->pds = lpass_macro_pds_init(dev); + if (IS_ERR(rx->pds)) + return PTR_ERR(rx->pds); base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err; + } rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config); + if (IS_ERR(rx->regmap)) { + ret = PTR_ERR(rx->regmap); + goto err; + } dev_set_drvdata(dev, rx); - rx->reset_swr = true; rx->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(rx->clks[2].clk, MCLK_FREQ); - clk_set_rate(rx->clks[3].clk, 2 * MCLK_FREQ); + clk_set_rate(rx->mclk, MCLK_FREQ); + clk_set_rate(rx->npl, 2 * MCLK_FREQ); - ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks); + ret = clk_prepare_enable(rx->macro); if (ret) - return ret; + goto err; + + ret = clk_prepare_enable(rx->dcodec); + if (ret) + goto err_dcodec; + + ret = clk_prepare_enable(rx->mclk); + if (ret) + goto err_mclk; + + ret = clk_prepare_enable(rx->npl); + if (ret) + goto err_npl; + + ret = clk_prepare_enable(rx->fsgen); + if (ret) + goto err_fsgen; - rx_macro_register_mclk_output(rx); + ret = rx_macro_register_mclk_output(rx); + if (ret) + goto err_clkout; ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv, rx_macro_dai, ARRAY_SIZE(rx_macro_dai)); if (ret) - clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks); + goto err_clkout; + + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; + +err_clkout: + clk_disable_unprepare(rx->fsgen); +err_fsgen: + clk_disable_unprepare(rx->npl); +err_npl: + clk_disable_unprepare(rx->mclk); +err_mclk: + clk_disable_unprepare(rx->dcodec); +err_dcodec: + clk_disable_unprepare(rx->macro); +err: + lpass_macro_pds_exit(rx->pds); return ret; } @@ -3571,23 +3640,84 @@ static int rx_macro_remove(struct platform_device *pdev) { struct rx_macro *rx = dev_get_drvdata(&pdev->dev); - of_clk_del_provider(pdev->dev.of_node); - clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks); + clk_disable_unprepare(rx->mclk); + clk_disable_unprepare(rx->npl); + clk_disable_unprepare(rx->fsgen); + clk_disable_unprepare(rx->macro); + clk_disable_unprepare(rx->dcodec); + + lpass_macro_pds_exit(rx->pds); + return 0; } static const struct of_device_id rx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-rx-macro" }, { .compatible = "qcom,sm8250-lpass-rx-macro" }, + { .compatible = "qcom,sm8450-lpass-rx-macro" }, + { .compatible = "qcom,sc8280xp-lpass-rx-macro" }, { } }; MODULE_DEVICE_TABLE(of, rx_macro_dt_match); +static int __maybe_unused rx_macro_runtime_suspend(struct device *dev) +{ + struct rx_macro *rx = dev_get_drvdata(dev); + + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); + + clk_disable_unprepare(rx->mclk); + clk_disable_unprepare(rx->npl); + clk_disable_unprepare(rx->fsgen); + + return 0; +} + +static int __maybe_unused rx_macro_runtime_resume(struct device *dev) +{ + struct rx_macro *rx = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(rx->mclk); + if (ret) { + dev_err(dev, "unable to prepare mclk\n"); + return ret; + } + + ret = clk_prepare_enable(rx->npl); + if (ret) { + dev_err(dev, "unable to prepare mclkx2\n"); + goto err_npl; + } + + ret = clk_prepare_enable(rx->fsgen); + if (ret) { + dev_err(dev, "unable to prepare fsgen\n"); + goto err_fsgen; + } + regcache_cache_only(rx->regmap, false); + regcache_sync(rx->regmap); + + return 0; +err_fsgen: + clk_disable_unprepare(rx->npl); +err_npl: + clk_disable_unprepare(rx->mclk); + + return ret; +} + +static const struct dev_pm_ops rx_macro_pm_ops = { + SET_RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL) +}; + static struct platform_driver rx_macro_driver = { .driver = { .name = "rx_macro", .of_match_table = rx_macro_dt_match, .suppress_bind_attrs = true, + .pm = &rx_macro_pm_ops, }, .probe = rx_macro_probe, .remove = rx_macro_remove, diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index a4c0a155af56..ee15cf6b98bb 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -6,6 +6,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -13,6 +14,8 @@ #include <linux/of_clk.h> #include <linux/clk-provider.h> +#include "lpass-macro-common.h" + #define CDC_TX_CLK_RST_CTRL_MCLK_CONTROL (0x0000) #define CDC_TX_MCLK_EN_MASK BIT(0) #define CDC_TX_MCLK_ENABLE BIT(0) @@ -256,16 +259,20 @@ struct tx_macro { struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; unsigned long active_ch_mask[TX_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS]; - unsigned long active_decimator[TX_MACRO_MAX_DAIS]; + int active_decimator[TX_MACRO_MAX_DAIS]; struct regmap *regmap; - struct clk_bulk_data clks[TX_NUM_CLKS_MAX]; + struct clk *mclk; + struct clk *npl; + struct clk *macro; + struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; bool dec_active[NUM_DECIMATORS]; - bool reset_swr; int tx_mclk_users; u16 dmic_clk_div; bool bcs_enable; int dec_mode[NUM_DECIMATORS]; + struct lpass_macro *pds; bool bcs_clk_en; }; #define to_tx_macro(_hw) container_of(_hw, struct tx_macro, hw) @@ -815,17 +822,23 @@ static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, struct tx_macro *tx = snd_soc_component_get_drvdata(component); if (enable) { + if (tx->active_decimator[dai_id] == dec_id) + return 0; + set_bit(dec_id, &tx->active_ch_mask[dai_id]); tx->active_ch_cnt[dai_id]++; tx->active_decimator[dai_id] = dec_id; } else { + if (tx->active_decimator[dai_id] == -1) + return 0; + tx->active_ch_cnt[dai_id]--; clear_bit(dec_id, &tx->active_ch_mask[dai_id]); tx->active_decimator[dai_id] = -1; } snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); - return 0; + return 1; } static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, @@ -1011,9 +1024,12 @@ static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol, int path = e->shift_l; struct tx_macro *tx = snd_soc_component_get_drvdata(component); + if (tx->dec_mode[path] == value) + return 0; + tx->dec_mode[path] = value; - return 0; + return 1; } static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol, @@ -1110,6 +1126,10 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) struct tx_macro *tx = snd_soc_component_get_drvdata(component); u16 decimator; + /* active decimator not set yet */ + if (tx->active_decimator[dai->id] == -1) + return 0; + decimator = tx->active_decimator[dai->id]; if (mute) @@ -1685,20 +1705,23 @@ static int swclk_gate_enable(struct clk_hw *hw) { struct tx_macro *tx = to_tx_macro(hw); struct regmap *regmap = tx->regmap; + int ret; + + ret = clk_prepare_enable(tx->mclk); + if (ret) { + dev_err(tx->dev, "failed to enable mclk\n"); + return ret; + } tx_macro_mclk_enable(tx, true); - if (tx->reset_swr) - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, - CDC_TX_SWR_RESET_MASK, - CDC_TX_SWR_RESET_ENABLE); + regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE); regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, CDC_TX_SWR_CLK_EN_MASK, CDC_TX_SWR_CLK_ENABLE); - if (tx->reset_swr) - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, - CDC_TX_SWR_RESET_MASK, 0x0); - tx->reset_swr = false; + regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + CDC_TX_SWR_RESET_MASK, 0x0); return 0; } @@ -1712,6 +1735,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_TX_SWR_CLK_EN_MASK, 0x0); tx_macro_mclk_enable(tx, false); + clk_disable_unprepare(tx->mclk); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -1739,17 +1763,16 @@ static const struct clk_ops swclk_gate_ops = { }; -static struct clk *tx_macro_register_mclk_output(struct tx_macro *tx) +static int tx_macro_register_mclk_output(struct tx_macro *tx) { struct device *dev = tx->dev; - struct device_node *np = dev->of_node; const char *parent_clk_name = NULL; const char *clk_name = "lpass-tx-mclk"; struct clk_hw *hw; struct clk_init_data init; int ret; - parent_clk_name = __clk_get_name(tx->clks[2].clk); + parent_clk_name = __clk_get_name(tx->npl); init.name = clk_name; init.ops = &swclk_gate_ops; @@ -1758,13 +1781,11 @@ static struct clk *tx_macro_register_mclk_output(struct tx_macro *tx) init.num_parents = 1; tx->hw.init = &init; hw = &tx->hw; - ret = clk_hw_register(tx->dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) - return ERR_PTR(ret); - - of_clk_add_provider(np, of_clk_src_simple_get, hw->clk); + return ret; - return NULL; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); } static const struct snd_soc_component_driver tx_macro_component_drv = { @@ -1790,21 +1811,35 @@ static int tx_macro_probe(struct platform_device *pdev) if (!tx) return -ENOMEM; - tx->clks[0].id = "macro"; - tx->clks[1].id = "dcodec"; - tx->clks[2].id = "mclk"; - tx->clks[3].id = "npl"; - tx->clks[4].id = "fsgen"; + tx->macro = devm_clk_get_optional(dev, "macro"); + if (IS_ERR(tx->macro)) + return PTR_ERR(tx->macro); - ret = devm_clk_bulk_get_optional(dev, TX_NUM_CLKS_MAX, tx->clks); - if (ret) { - dev_err(dev, "Error getting RX Clocks (%d)\n", ret); - return ret; - } + tx->dcodec = devm_clk_get_optional(dev, "dcodec"); + if (IS_ERR(tx->dcodec)) + return PTR_ERR(tx->dcodec); + + tx->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(tx->mclk)) + return PTR_ERR(tx->mclk); + + tx->npl = devm_clk_get(dev, "npl"); + if (IS_ERR(tx->npl)) + return PTR_ERR(tx->npl); + + tx->fsgen = devm_clk_get(dev, "fsgen"); + if (IS_ERR(tx->fsgen)) + return PTR_ERR(tx->fsgen); + + tx->pds = lpass_macro_pds_init(dev); + if (IS_ERR(tx->pds)) + return PTR_ERR(tx->pds); base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err; + } /* Update defaults for lpass sc7280 */ if (of_device_is_compatible(np, "qcom,sc7280-lpass-tx-macro")) { @@ -1821,30 +1856,69 @@ static int tx_macro_probe(struct platform_device *pdev) } tx->regmap = devm_regmap_init_mmio(dev, base, &tx_regmap_config); + if (IS_ERR(tx->regmap)) { + ret = PTR_ERR(tx->regmap); + goto err; + } dev_set_drvdata(dev, tx); - tx->reset_swr = true; tx->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(tx->clks[2].clk, MCLK_FREQ); - clk_set_rate(tx->clks[3].clk, 2 * MCLK_FREQ); + clk_set_rate(tx->mclk, MCLK_FREQ); + clk_set_rate(tx->npl, 2 * MCLK_FREQ); - ret = clk_bulk_prepare_enable(TX_NUM_CLKS_MAX, tx->clks); + ret = clk_prepare_enable(tx->macro); if (ret) - return ret; + goto err; - tx_macro_register_mclk_output(tx); + ret = clk_prepare_enable(tx->dcodec); + if (ret) + goto err_dcodec; + + ret = clk_prepare_enable(tx->mclk); + if (ret) + goto err_mclk; + + ret = clk_prepare_enable(tx->npl); + if (ret) + goto err_npl; + + ret = clk_prepare_enable(tx->fsgen); + if (ret) + goto err_fsgen; + + ret = tx_macro_register_mclk_output(tx); + if (ret) + goto err_clkout; ret = devm_snd_soc_register_component(dev, &tx_macro_component_drv, tx_macro_dai, ARRAY_SIZE(tx_macro_dai)); if (ret) - goto err; - return ret; + goto err_clkout; + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; + +err_clkout: + clk_disable_unprepare(tx->fsgen); +err_fsgen: + clk_disable_unprepare(tx->npl); +err_npl: + clk_disable_unprepare(tx->mclk); +err_mclk: + clk_disable_unprepare(tx->dcodec); +err_dcodec: + clk_disable_unprepare(tx->macro); err: - clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks); + lpass_macro_pds_exit(tx->pds); return ret; } @@ -1853,16 +1927,75 @@ static int tx_macro_remove(struct platform_device *pdev) { struct tx_macro *tx = dev_get_drvdata(&pdev->dev); - of_clk_del_provider(pdev->dev.of_node); + clk_disable_unprepare(tx->macro); + clk_disable_unprepare(tx->dcodec); + clk_disable_unprepare(tx->mclk); + clk_disable_unprepare(tx->npl); + clk_disable_unprepare(tx->fsgen); + + lpass_macro_pds_exit(tx->pds); + + return 0; +} + +static int __maybe_unused tx_macro_runtime_suspend(struct device *dev) +{ + struct tx_macro *tx = dev_get_drvdata(dev); + + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); + + clk_disable_unprepare(tx->mclk); + clk_disable_unprepare(tx->npl); + clk_disable_unprepare(tx->fsgen); + + return 0; +} + +static int __maybe_unused tx_macro_runtime_resume(struct device *dev) +{ + struct tx_macro *tx = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(tx->mclk); + if (ret) { + dev_err(dev, "unable to prepare mclk\n"); + return ret; + } + + ret = clk_prepare_enable(tx->npl); + if (ret) { + dev_err(dev, "unable to prepare npl\n"); + goto err_npl; + } + + ret = clk_prepare_enable(tx->fsgen); + if (ret) { + dev_err(dev, "unable to prepare fsgen\n"); + goto err_fsgen; + } - clk_bulk_disable_unprepare(TX_NUM_CLKS_MAX, tx->clks); + regcache_cache_only(tx->regmap, false); + regcache_sync(tx->regmap); return 0; +err_fsgen: + clk_disable_unprepare(tx->npl); +err_npl: + clk_disable_unprepare(tx->mclk); + + return ret; } +static const struct dev_pm_ops tx_macro_pm_ops = { + SET_RUNTIME_PM_OPS(tx_macro_runtime_suspend, tx_macro_runtime_resume, NULL) +}; + static const struct of_device_id tx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-tx-macro" }, { .compatible = "qcom,sm8250-lpass-tx-macro" }, + { .compatible = "qcom,sm8450-lpass-tx-macro" }, + { .compatible = "qcom,sc8280xp-lpass-tx-macro" }, { } }; MODULE_DEVICE_TABLE(of, tx_macro_dt_match); @@ -1871,6 +2004,7 @@ static struct platform_driver tx_macro_driver = { .name = "tx_macro", .of_match_table = tx_macro_dt_match, .suppress_bind_attrs = true, + .pm = &tx_macro_pm_ops, }, .probe = tx_macro_probe, .remove = tx_macro_remove, diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 11147e35689b..b0b6cf29cba3 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -9,18 +9,26 @@ #include <linux/of_clk.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> +#include "lpass-macro-common.h" + /* VA macro registers */ #define CDC_VA_CLK_RST_CTRL_MCLK_CONTROL (0x0000) #define CDC_VA_MCLK_CONTROL_EN BIT(0) #define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004) #define CDC_VA_FS_CONTROL_EN BIT(0) +#define CDC_VA_FS_COUNTER_CLR BIT(1) #define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008) +#define CDC_VA_SWR_RESET_MASK BIT(1) +#define CDC_VA_SWR_RESET_ENABLE BIT(1) +#define CDC_VA_SWR_CLK_EN_MASK BIT(0) +#define CDC_VA_SWR_CLK_ENABLE BIT(0) #define CDC_VA_TOP_CSR_TOP_CFG0 (0x0080) #define CDC_VA_FS_BROADCAST_EN BIT(1) #define CDC_VA_TOP_CSR_DMIC0_CTL (0x0084) @@ -62,6 +70,8 @@ #define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0) #define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4) #define CDC_VA_TOP_CSR_SWR_MIC_CTL2 (0x00D8) +#define CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK (0xEE) +#define CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1 (0xCC) #define CDC_VA_TOP_CSR_SWR_CTRL (0x00DC) #define CDC_VA_INP_MUX_ADC_MUX0_CFG0 (0x0100) #define CDC_VA_INP_MUX_ADC_MUX0_CFG1 (0x0104) @@ -190,11 +200,16 @@ struct va_macro { unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS]; u16 dmic_clk_div; + bool has_swr_master; int dec_mode[VA_MACRO_NUM_DECIMATORS]; struct regmap *regmap; - struct clk_bulk_data clks[VA_NUM_CLKS_MAX]; + struct clk *mclk; + struct clk *macro; + struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; + struct lpass_macro *pds; s32 dmic_0_1_clk_cnt; s32 dmic_2_3_clk_cnt; @@ -208,6 +223,18 @@ struct va_macro { #define to_va_macro(_hw) container_of(_hw, struct va_macro, hw) +struct va_macro_data { + bool has_swr_master; +}; + +static const struct va_macro_data sm8250_va_data = { + .has_swr_master = false, +}; + +static const struct va_macro_data sm8450_va_data = { + .has_swr_master = true, +}; + static bool va_is_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -317,6 +344,9 @@ static bool va_is_rw_register(struct device *dev, unsigned int reg) case CDC_VA_TOP_CSR_DMIC2_CTL: case CDC_VA_TOP_CSR_DMIC3_CTL: case CDC_VA_TOP_CSR_DMIC_CFG: + case CDC_VA_TOP_CSR_SWR_MIC_CTL0: + case CDC_VA_TOP_CSR_SWR_MIC_CTL1: + case CDC_VA_TOP_CSR_SWR_MIC_CTL2: case CDC_VA_TOP_CSR_DEBUG_BUS: case CDC_VA_TOP_CSR_DEBUG_EN: case CDC_VA_TOP_CSR_TX_I2S_CTL: @@ -416,9 +446,12 @@ static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, CDC_VA_MCLK_CONTROL_EN, CDC_VA_MCLK_CONTROL_EN); - + /* clear the fs counter */ regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, - CDC_VA_FS_CONTROL_EN, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR); + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, CDC_VA_FS_CONTROL_EN); regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0, @@ -461,9 +494,9 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - return va_macro_mclk_enable(va, true); + return clk_prepare_enable(va->fsgen); case SND_SOC_DAPM_POST_PMD: - return va_macro_mclk_enable(va, false); + clk_disable_unprepare(va->fsgen); } return 0; @@ -780,7 +813,7 @@ static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int path = e->shift_l; - ucontrol->value.integer.value[0] = va->dec_mode[path]; + ucontrol->value.enumerated.item[0] = va->dec_mode[path]; return 0; } @@ -789,7 +822,7 @@ static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int path = e->shift_l; struct va_macro *va = snd_soc_component_get_drvdata(comp); @@ -1295,12 +1328,36 @@ static const struct snd_soc_component_driver va_macro_component_drv = { static int fsgen_gate_enable(struct clk_hw *hw) { - return va_macro_mclk_enable(to_va_macro(hw), true); + struct va_macro *va = to_va_macro(hw); + struct regmap *regmap = va->regmap; + int ret; + + ret = va_macro_mclk_enable(va, true); + if (!va->has_swr_master) + return ret; + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_RESET_MASK, CDC_VA_SWR_RESET_ENABLE); + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_CLK_EN_MASK, + CDC_VA_SWR_CLK_ENABLE); + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_RESET_MASK, 0x0); + + return ret; } static void fsgen_gate_disable(struct clk_hw *hw) { - va_macro_mclk_enable(to_va_macro(hw), false); + struct va_macro *va = to_va_macro(hw); + struct regmap *regmap = va->regmap; + + if (va->has_swr_master) + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_CLK_EN_MASK, 0x0); + + va_macro_mclk_enable(va, false); } static int fsgen_gate_is_enabled(struct clk_hw *hw) @@ -1321,7 +1378,7 @@ static const struct clk_ops fsgen_gate_ops = { static int va_macro_register_fsgen_output(struct va_macro *va) { - struct clk *parent = va->clks[2].clk; + struct clk *parent = va->mclk; struct device *dev = va->dev; struct device_node *np = dev->of_node; const char *parent_clk_name; @@ -1394,6 +1451,7 @@ undefined_rate: static int va_macro_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct va_macro_data *data; struct va_macro *va; void __iomem *base; u32 sample_rate = 0; @@ -1404,15 +1462,22 @@ static int va_macro_probe(struct platform_device *pdev) return -ENOMEM; va->dev = dev; - va->clks[0].id = "macro"; - va->clks[1].id = "dcodec"; - va->clks[2].id = "mclk"; - ret = devm_clk_bulk_get_optional(dev, VA_NUM_CLKS_MAX, va->clks); - if (ret) { - dev_err(dev, "Error getting VA Clocks (%d)\n", ret); - return ret; - } + va->macro = devm_clk_get_optional(dev, "macro"); + if (IS_ERR(va->macro)) + return PTR_ERR(va->macro); + + va->dcodec = devm_clk_get_optional(dev, "dcodec"); + if (IS_ERR(va->dcodec)) + return PTR_ERR(va->dcodec); + + va->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(va->mclk)) + return PTR_ERR(va->mclk); + + va->pds = lpass_macro_pds_init(dev); + if (IS_ERR(va->pds)) + return PTR_ERR(va->pds); ret = of_property_read_u32(dev->of_node, "qcom,dmic-sample-rate", &sample_rate); @@ -1421,16 +1486,12 @@ static int va_macro_probe(struct platform_device *pdev) va->dmic_clk_div = VA_MACRO_CLK_DIV_2; } else { ret = va_macro_validate_dmic_sample_rate(sample_rate, va); - if (!ret) - return -EINVAL; + if (!ret) { + ret = -EINVAL; + goto err; + } } - /* mclk rate */ - clk_set_rate(va->clks[1].clk, VA_MACRO_MCLK_FREQ); - ret = clk_bulk_prepare_enable(VA_NUM_CLKS_MAX, va->clks); - if (ret) - return ret; - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { ret = PTR_ERR(base); @@ -1444,20 +1505,71 @@ static int va_macro_probe(struct platform_device *pdev) } dev_set_drvdata(dev, va); - ret = va_macro_register_fsgen_output(va); + + data = of_device_get_match_data(dev); + va->has_swr_master = data->has_swr_master; + + /* mclk rate */ + clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); + + ret = clk_prepare_enable(va->macro); if (ret) goto err; + ret = clk_prepare_enable(va->dcodec); + if (ret) + goto err_dcodec; + + ret = clk_prepare_enable(va->mclk); + if (ret) + goto err_mclk; + + ret = va_macro_register_fsgen_output(va); + if (ret) + goto err_clkout; + + va->fsgen = clk_hw_get_clk(&va->hw, "fsgen"); + if (IS_ERR(va->fsgen)) { + ret = PTR_ERR(va->fsgen); + goto err_clkout; + } + + if (va->has_swr_master) { + /* Set default CLK div to 1 */ + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL1, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL2, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + + } + ret = devm_snd_soc_register_component(dev, &va_macro_component_drv, va_macro_dais, ARRAY_SIZE(va_macro_dais)); if (ret) - goto err; + goto err_clkout; - return ret; + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; + +err_clkout: + clk_disable_unprepare(va->mclk); +err_mclk: + clk_disable_unprepare(va->dcodec); +err_dcodec: + clk_disable_unprepare(va->macro); err: - clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); + lpass_macro_pds_exit(va->pds); return ret; } @@ -1466,14 +1578,54 @@ static int va_macro_remove(struct platform_device *pdev) { struct va_macro *va = dev_get_drvdata(&pdev->dev); - clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); + clk_disable_unprepare(va->mclk); + clk_disable_unprepare(va->dcodec); + clk_disable_unprepare(va->macro); + + lpass_macro_pds_exit(va->pds); + + return 0; +} + +static int __maybe_unused va_macro_runtime_suspend(struct device *dev) +{ + struct va_macro *va = dev_get_drvdata(dev); + + regcache_cache_only(va->regmap, true); + regcache_mark_dirty(va->regmap); + + clk_disable_unprepare(va->mclk); return 0; } +static int __maybe_unused va_macro_runtime_resume(struct device *dev) +{ + struct va_macro *va = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(va->mclk); + if (ret) { + dev_err(va->dev, "unable to prepare mclk\n"); + return ret; + } + + regcache_cache_only(va->regmap, false); + regcache_sync(va->regmap); + + return 0; +} + + +static const struct dev_pm_ops va_macro_pm_ops = { + SET_RUNTIME_PM_OPS(va_macro_runtime_suspend, va_macro_runtime_resume, NULL) +}; + static const struct of_device_id va_macro_dt_match[] = { - { .compatible = "qcom,sc7280-lpass-va-macro" }, - { .compatible = "qcom,sm8250-lpass-va-macro" }, + { .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data }, + { .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data }, + { .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data }, + { .compatible = "qcom,sc8280xp-lpass-va-macro", .data = &sm8450_va_data }, {} }; MODULE_DEVICE_TABLE(of, va_macro_dt_match); @@ -1483,6 +1635,7 @@ static struct platform_driver va_macro_driver = { .name = "va_macro", .of_match_table = va_macro_dt_match, .suppress_bind_attrs = true, + .pm = &va_macro_pm_ops, }, .probe = va_macro_probe, .remove = va_macro_remove, diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 75baf8eb7029..5e0abefe7cce 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -10,6 +10,7 @@ #include <linux/clk-provider.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <linux/pm_runtime.h> #include <linux/of_platform.h> #include <sound/tlv.h> #include "lpass-wsa-macro.h" @@ -337,7 +338,6 @@ struct wsa_macro { int ec_hq[WSA_MACRO_RX1 + 1]; u16 prim_int_users[WSA_MACRO_RX1 + 1]; u16 wsa_mclk_users; - bool reset_swr; unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS]; int rx_port_value[WSA_MACRO_RX_MAX]; @@ -347,7 +347,11 @@ struct wsa_macro { int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX]; int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX]; struct regmap *regmap; - struct clk_bulk_data clks[WSA_NUM_CLKS_MAX]; + struct clk *mclk; + struct clk *npl; + struct clk *macro; + struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; }; #define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw) @@ -2256,30 +2260,31 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) struct regmap *regmap = wsa->regmap; if (enable) { + int ret; + + ret = clk_prepare_enable(wsa->mclk); + if (ret) { + dev_err(wsa->dev, "failed to enable mclk\n"); + return ret; + } wsa_macro_mclk_enable(wsa, true); /* reset swr ip */ - if (wsa->reset_swr) - regmap_update_bits(regmap, - CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, - CDC_WSA_SWR_RST_EN_MASK, - CDC_WSA_SWR_RST_ENABLE); + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE); regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, CDC_WSA_SWR_CLK_ENABLE); /* Bring out of reset */ - if (wsa->reset_swr) - regmap_update_bits(regmap, - CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, - CDC_WSA_SWR_RST_EN_MASK, - CDC_WSA_SWR_RST_DISABLE); - wsa->reset_swr = false; + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE); } else { regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, 0); wsa_macro_mclk_enable(wsa, false); + clk_disable_unprepare(wsa->mclk); } return 0; @@ -2350,7 +2355,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) struct clk_init_data init; int ret; - parent_clk_name = __clk_get_name(wsa->clks[2].clk); + parent_clk_name = __clk_get_name(wsa->npl); init.name = clk_name; init.ops = &swclk_gate_ops; @@ -2388,49 +2393,92 @@ static int wsa_macro_probe(struct platform_device *pdev) if (!wsa) return -ENOMEM; - wsa->clks[0].id = "macro"; - wsa->clks[1].id = "dcodec"; - wsa->clks[2].id = "mclk"; - wsa->clks[3].id = "npl"; - wsa->clks[4].id = "fsgen"; + wsa->macro = devm_clk_get_optional(dev, "macro"); + if (IS_ERR(wsa->macro)) + return PTR_ERR(wsa->macro); - ret = devm_clk_bulk_get(dev, WSA_NUM_CLKS_MAX, wsa->clks); - if (ret) { - dev_err(dev, "Error getting WSA Clocks (%d)\n", ret); - return ret; - } + wsa->dcodec = devm_clk_get_optional(dev, "dcodec"); + if (IS_ERR(wsa->dcodec)) + return PTR_ERR(wsa->dcodec); + + wsa->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(wsa->mclk)) + return PTR_ERR(wsa->mclk); + + wsa->npl = devm_clk_get(dev, "npl"); + if (IS_ERR(wsa->npl)) + return PTR_ERR(wsa->npl); + + wsa->fsgen = devm_clk_get(dev, "fsgen"); + if (IS_ERR(wsa->fsgen)) + return PTR_ERR(wsa->fsgen); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config); + if (IS_ERR(wsa->regmap)) + return PTR_ERR(wsa->regmap); dev_set_drvdata(dev, wsa); - wsa->reset_swr = true; wsa->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(wsa->clks[2].clk, WSA_MACRO_MCLK_FREQ); - clk_set_rate(wsa->clks[3].clk, WSA_MACRO_MCLK_FREQ); + clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); + clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); - ret = clk_bulk_prepare_enable(WSA_NUM_CLKS_MAX, wsa->clks); + ret = clk_prepare_enable(wsa->macro); if (ret) - return ret; + goto err; + + ret = clk_prepare_enable(wsa->dcodec); + if (ret) + goto err_dcodec; + + ret = clk_prepare_enable(wsa->mclk); + if (ret) + goto err_mclk; + + ret = clk_prepare_enable(wsa->npl); + if (ret) + goto err_npl; + + ret = clk_prepare_enable(wsa->fsgen); + if (ret) + goto err_fsgen; + + ret = wsa_macro_register_mclk_output(wsa); + if (ret) + goto err_clkout; - wsa_macro_register_mclk_output(wsa); ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv, wsa_macro_dai, ARRAY_SIZE(wsa_macro_dai)); if (ret) - goto err; + goto err_clkout; - return ret; -err: - clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks); + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +err_clkout: + clk_disable_unprepare(wsa->fsgen); +err_fsgen: + clk_disable_unprepare(wsa->npl); +err_npl: + clk_disable_unprepare(wsa->mclk); +err_mclk: + clk_disable_unprepare(wsa->dcodec); +err_dcodec: + clk_disable_unprepare(wsa->macro); +err: return ret; } @@ -2439,14 +2487,73 @@ static int wsa_macro_remove(struct platform_device *pdev) { struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); - clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks); + clk_disable_unprepare(wsa->macro); + clk_disable_unprepare(wsa->dcodec); + clk_disable_unprepare(wsa->mclk); + clk_disable_unprepare(wsa->npl); + clk_disable_unprepare(wsa->fsgen); + + return 0; +} + +static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev) +{ + struct wsa_macro *wsa = dev_get_drvdata(dev); + + regcache_cache_only(wsa->regmap, true); + regcache_mark_dirty(wsa->regmap); + + clk_disable_unprepare(wsa->mclk); + clk_disable_unprepare(wsa->npl); + clk_disable_unprepare(wsa->fsgen); + + return 0; +} + +static int __maybe_unused wsa_macro_runtime_resume(struct device *dev) +{ + struct wsa_macro *wsa = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(wsa->mclk); + if (ret) { + dev_err(dev, "unable to prepare mclk\n"); + return ret; + } + + ret = clk_prepare_enable(wsa->npl); + if (ret) { + dev_err(dev, "unable to prepare mclkx2\n"); + goto err_npl; + } + + ret = clk_prepare_enable(wsa->fsgen); + if (ret) { + dev_err(dev, "unable to prepare fsgen\n"); + goto err_fsgen; + } + + regcache_cache_only(wsa->regmap, false); + regcache_sync(wsa->regmap); return 0; +err_fsgen: + clk_disable_unprepare(wsa->npl); +err_npl: + clk_disable_unprepare(wsa->mclk); + + return ret; } +static const struct dev_pm_ops wsa_macro_pm_ops = { + SET_RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL) +}; + static const struct of_device_id wsa_macro_dt_match[] = { {.compatible = "qcom,sc7280-lpass-wsa-macro"}, {.compatible = "qcom,sm8250-lpass-wsa-macro"}, + {.compatible = "qcom,sm8450-lpass-wsa-macro"}, + {.compatible = "qcom,sc8280xp-lpass-wsa-macro" }, {} }; MODULE_DEVICE_TABLE(of, wsa_macro_dt_match); @@ -2455,6 +2562,7 @@ static struct platform_driver wsa_macro_driver = { .driver = { .name = "wsa_macro", .of_match_table = wsa_macro_dt_match, + .pm = &wsa_macro_pm_ops, }, .probe = wsa_macro_probe, .remove = wsa_macro_remove, diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 272041c6236a..b9f19fbd2911 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -618,7 +618,13 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol, end: snd_soc_dapm_mutex_unlock(dapm); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + if (ret < 0) { + dev_err(madera->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } EXPORT_SYMBOL_GPL(madera_out1_demux_put); @@ -893,7 +899,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; const int adsp_num = e->shift_l; const unsigned int item = ucontrol->value.enumerated.item[0]; - int ret; + int ret = 0; if (item >= e->items) return -EINVAL; @@ -910,10 +916,10 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, "Cannot change '%s' while in use by active audio paths\n", kcontrol->id.name); ret = -EBUSY; - } else { + } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) { /* Volatile register so defer until the codec is powered up */ priv->adsp_rate_cache[adsp_num] = e->values[item]; - ret = 0; + ret = 1; } mutex_unlock(&priv->rate_lock); diff --git a/sound/soc/codecs/max9759.c b/sound/soc/codecs/max9759.c index 00e9d4fd1651..bc57d7687f16 100644 --- a/sound/soc/codecs/max9759.c +++ b/sound/soc/codecs/max9759.c @@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); struct max9759 *priv = snd_soc_component_get_drvdata(c); - if (ucontrol->value.integer.value[0] > 3) + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > 3) return -EINVAL; priv->gain = ucontrol->value.integer.value[0]; @@ -140,7 +141,6 @@ static int max9759_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct max9759 *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -149,29 +149,20 @@ static int max9759_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_shutdown)) { - err = PTR_ERR(priv->gpiod_shutdown); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'shutdown' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_shutdown)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_shutdown), + "Failed to get 'shutdown' gpio"); priv->gpiod_mute = devm_gpiod_get(dev, "mute", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_mute)) { - err = PTR_ERR(priv->gpiod_mute); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'mute' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_mute)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_mute), + "Failed to get 'mute' gpio"); priv->is_mute = true; priv->gpiod_gain = devm_gpiod_get_array(dev, "gain", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_gain)) { - err = PTR_ERR(priv->gpiod_gain); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'gain' gpios: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_gain)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_gain), + "Failed to get 'gain' gpios"); priv->gain = 0; if (priv->gpiod_gain->ndescs != 2) { diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 39dda1b03b3d..d711eb1da0a8 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -167,8 +167,7 @@ static const struct regmap_config max9768_i2c_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int max9768_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9768_i2c_probe(struct i2c_client *client) { struct max9768 *max9768; struct max9768_pdata *pdata = client->dev.platform_data; @@ -215,7 +214,7 @@ static struct i2c_driver max9768_i2c_driver = { .driver = { .name = "max9768", }, - .probe = max9768_i2c_probe, + .probe_new = max9768_i2c_probe, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index f8e49e45ce33..405ec16be2b6 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -474,6 +474,9 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { max98088_mic2pre_get, max98088_mic2pre_set, max98088_micboost_tlv), + SOC_SINGLE("Noise Gate Threshold", M98088_REG_40_MICAGC_THRESH, + 4, 15, 0), + SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1), SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1), @@ -1156,20 +1159,18 @@ static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai, if (fmt != cdata->fmt) { cdata->fmt = fmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Slave mode PLL */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Consumer mode PLL */ snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI, 0x80); snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO, 0x00); break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ reg14val |= M98088_DAI_MAS; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "Clock mode unsupported"); return -EINVAL; @@ -1227,20 +1228,18 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai, if (fmt != cdata->fmt) { cdata->fmt = fmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Slave mode PLL */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Consumer mode PLL */ snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI, 0x80); snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO, 0x00); break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ reg1Cval |= M98088_DAI_MAS; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "Clock mode unsupported"); return -EINVAL; @@ -1738,46 +1737,44 @@ static const struct snd_soc_component_driver soc_component_dev_max98088 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max98088_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id max98088_i2c_id[] = { + { "max98088", MAX98088 }, + { "max98089", MAX98089 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); + +static int max98088_i2c_probe(struct i2c_client *i2c) { - struct max98088_priv *max98088; - int ret; + struct max98088_priv *max98088; + const struct i2c_device_id *id; - max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv), - GFP_KERNEL); - if (max98088 == NULL) - return -ENOMEM; + max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv), + GFP_KERNEL); + if (max98088 == NULL) + return -ENOMEM; - max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); - if (IS_ERR(max98088->regmap)) - return PTR_ERR(max98088->regmap); + max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap); + if (IS_ERR(max98088->regmap)) + return PTR_ERR(max98088->regmap); max98088->mclk = devm_clk_get(&i2c->dev, "mclk"); if (IS_ERR(max98088->mclk)) if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER) return PTR_ERR(max98088->mclk); - max98088->devtype = id->driver_data; + id = i2c_match_id(max98088_i2c_id, i2c); + max98088->devtype = id->driver_data; - i2c_set_clientdata(i2c, max98088); - max98088->pdata = i2c->dev.platform_data; + i2c_set_clientdata(i2c, max98088); + max98088->pdata = i2c->dev.platform_data; - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_max98088, &max98088_dai[0], 2); - return ret; + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088, + &max98088_dai[0], 2); } -static const struct i2c_device_id max98088_i2c_id[] = { - { "max98088", MAX98088 }, - { "max98089", MAX98089 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); - #if defined(CONFIG_OF) static const struct of_device_id max98088_of_match[] = { { .compatible = "maxim,max98088" }, @@ -1792,7 +1789,7 @@ static struct i2c_driver max98088_i2c_driver = { .name = "max98088", .of_match_table = of_match_ptr(max98088_of_match), }, - .probe = max98088_i2c_probe, + .probe_new = max98088_i2c_probe, .id_table = max98088_i2c_id, }; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index b45ec35cd63c..06ed2a938108 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -393,9 +393,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mask = (1 << fls(mc->max)) - 1; - unsigned int sel = ucontrol->value.integer.value[0]; + int sel_unchecked = ucontrol->value.integer.value[0]; + unsigned int sel; unsigned int val = snd_soc_component_read(component, mc->reg); unsigned int *select; + int change; switch (mc->reg) { case M98090_REG_MIC1_INPUT_LEVEL: @@ -413,6 +415,11 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, val = (val >> mc->shift) & mask; + if (sel_unchecked < 0 || sel_unchecked > mc->max) + return -EINVAL; + sel = sel_unchecked; + + change = *select != sel; *select = sel; /* Setting a volume is only valid if it is already On */ @@ -427,7 +434,7 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol, mask << mc->shift, sel << mc->shift); - return 0; + return change; } static const char *max98090_perf_pwr_text[] = @@ -1584,9 +1591,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, cdata->fmt = fmt; regval = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Set to slave mode PLL - MAS mode off */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Set to consumer mode PLL - MAS mode off */ snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB, 0x00); snd_soc_component_write(component, @@ -1595,8 +1602,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, M98090_USE_M1_MASK, 0); max98090->master = false; break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ if (max98090->tdm_slots == 4) { /* TDM */ regval |= M98090_MAS_MASK | @@ -1612,8 +1619,6 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, } max98090->master = true; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "DAI clock mode unsupported"); return -EINVAL; @@ -2514,7 +2519,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98090 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98090_regmap = { @@ -2529,8 +2533,14 @@ static const struct regmap_config max98090_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98090_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static const struct i2c_device_id max98090_i2c_id[] = { + { "max98090", MAX98090 }, + { "max98091", MAX98091 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); + +static int max98090_i2c_probe(struct i2c_client *i2c) { struct max98090_priv *max98090; const struct acpi_device_id *acpi_id; @@ -2552,7 +2562,9 @@ static int max98090_i2c_probe(struct i2c_client *i2c, return -EINVAL; } driver_data = acpi_id->driver_data; - } else if (i2c_id) { + } else { + const struct i2c_device_id *i2c_id = + i2c_match_id(max98090_i2c_id, i2c); driver_data = i2c_id->driver_data; } @@ -2603,11 +2615,9 @@ static void max98090_i2c_shutdown(struct i2c_client *i2c) msleep(40); } -static int max98090_i2c_remove(struct i2c_client *client) +static void max98090_i2c_remove(struct i2c_client *client) { max98090_i2c_shutdown(client); - - return 0; } #ifdef CONFIG_PM @@ -2659,13 +2669,6 @@ static const struct dev_pm_ops max98090_pm = { SET_SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume) }; -static const struct i2c_device_id max98090_i2c_id[] = { - { "max98090", MAX98090 }, - { "max98091", MAX98091 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); - #ifdef CONFIG_OF static const struct of_device_id max98090_of_match[] = { { .compatible = "maxim,max98090", }, @@ -2690,7 +2693,7 @@ static struct i2c_driver max98090_i2c_driver = { .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), }, - .probe = max98090_i2c_probe, + .probe_new = max98090_i2c_probe, .shutdown = max98090_i2c_shutdown, .remove = max98090_i2c_remove, .id_table = max98090_i2c_id, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 736cd70be725..44aa58fcc23f 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1168,20 +1168,18 @@ static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai, if (fmt != cdata->fmt) { cdata->fmt = fmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Slave mode PLL */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Consumer mode PLL */ snd_soc_component_write(component, M98095_028_DAI1_CLKCFG_HI, 0x80); snd_soc_component_write(component, M98095_029_DAI1_CLKCFG_LO, 0x00); break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ regval |= M98095_DAI_MAS; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "Clock mode unsupported"); return -EINVAL; @@ -1236,20 +1234,18 @@ static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai, if (fmt != cdata->fmt) { cdata->fmt = fmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Slave mode PLL */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Consumer mode PLL */ snd_soc_component_write(component, M98095_032_DAI2_CLKCFG_HI, 0x80); snd_soc_component_write(component, M98095_033_DAI2_CLKCFG_LO, 0x00); break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ regval |= M98095_DAI_MAS; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "Clock mode unsupported"); return -EINVAL; @@ -1305,20 +1301,18 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai, if (fmt != cdata->fmt) { cdata->fmt = fmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* Slave mode PLL */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* Consumer mode PLL */ snd_soc_component_write(component, M98095_03C_DAI3_CLKCFG_HI, 0x80); snd_soc_component_write(component, M98095_03D_DAI3_CLKCFG_LO, 0x00); break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Set to master mode */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Set to provider mode */ regval |= M98095_DAI_MAS; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "Clock mode unsupported"); return -EINVAL; @@ -2109,14 +2103,19 @@ static const struct snd_soc_component_driver soc_component_dev_max98095 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max98095_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id max98095_i2c_id[] = { + { "max98095", MAX98095 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); + +static int max98095_i2c_probe(struct i2c_client *i2c) { struct max98095_priv *max98095; int ret; + const struct i2c_device_id *id; max98095 = devm_kzalloc(&i2c->dev, sizeof(struct max98095_priv), GFP_KERNEL); @@ -2132,6 +2131,7 @@ static int max98095_i2c_probe(struct i2c_client *i2c, return ret; } + id = i2c_match_id(max98095_i2c_id, i2c); max98095->devtype = id->driver_data; i2c_set_clientdata(i2c, max98095); max98095->pdata = i2c->dev.platform_data; @@ -2142,12 +2142,6 @@ static int max98095_i2c_probe(struct i2c_client *i2c, return ret; } -static const struct i2c_device_id max98095_i2c_id[] = { - { "max98095", MAX98095 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); - #ifdef CONFIG_OF static const struct of_device_id max98095_of_match[] = { { .compatible = "maxim,max98095", }, @@ -2161,7 +2155,7 @@ static struct i2c_driver max98095_i2c_driver = { .name = "max98095", .of_match_table = of_match_ptr(max98095_of_match), }, - .probe = max98095_i2c_probe, + .probe_new = max98095_i2c_probe, .id_table = max98095_i2c_id, }; diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 918812763884..2a2b286f1747 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -93,7 +93,6 @@ static const struct snd_soc_component_driver max98357a_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops max98357a_dai_ops = { diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index e424779db02b..bac9d1bcf60a 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -184,8 +184,8 @@ static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai, struct max98371_priv *max98371 = snd_soc_component_get_drvdata(component); unsigned int val = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: dev_err(component->dev, "DAI clock mode unsupported"); @@ -351,7 +351,6 @@ static const struct snd_soc_component_driver max98371_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98371_regmap = { @@ -365,8 +364,7 @@ static const struct regmap_config max98371_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98371_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98371_i2c_probe(struct i2c_client *i2c) { struct max98371_priv *max98371; int ret, reg; @@ -421,7 +419,7 @@ static struct i2c_driver max98371_i2c_driver = { .name = "max98371", .of_match_table = of_match_ptr(max98371_of_match), }, - .probe = max98371_i2c_probe, + .probe_new = max98371_i2c_probe, .id_table = max98371_i2c_id, }; diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index ddb6436835d7..3e04c7f0cce4 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -442,7 +442,6 @@ static bool max98373_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3: - case MAX98373_R203E_AMP_PATH_GAIN: case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK: case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK: case MAX98373_R20B6_BDE_CUR_STATE_READBACK: @@ -516,8 +515,7 @@ static const struct regmap_config max98373_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98373_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98373_i2c_probe(struct i2c_client *i2c) { int ret = 0; int reg = 0; @@ -622,7 +620,7 @@ static struct i2c_driver max98373_i2c_driver = { .acpi_match_table = ACPI_PTR(max98373_acpi_match), .pm = &max98373_pm, }, - .probe = max98373_i2c_probe, + .probe_new = max98373_i2c_probe, .id_table = max98373_i2c_id, }; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index dc520effc61c..899965b19d12 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -281,6 +281,8 @@ static __maybe_unused int max98373_resume(struct device *dev) msecs_to_jiffies(MAX98373_PROBE_TIMEOUT)); if (!time) { dev_err(dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } @@ -741,7 +743,7 @@ static int max98373_sdw_set_tdm_slot(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops max98373_dai_sdw_ops = { .hw_params = max98373_sdw_dai_hw_params, .hw_free = max98373_pcm_hw_free, - .set_sdw_stream = max98373_set_sdw_stream, + .set_stream = max98373_set_sdw_stream, .shutdown = max98373_shutdown, .set_tdm_slot = max98373_sdw_set_tdm_slot, }; @@ -862,6 +864,16 @@ static int max98373_sdw_probe(struct sdw_slave *slave, return max98373_init(slave, regmap); } +static int max98373_sdw_remove(struct sdw_slave *slave) +{ + struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev); + + if (max98373->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + #if defined(CONFIG_OF) static const struct of_device_id max98373_of_match[] = { { .compatible = "maxim,max98373", }, @@ -893,7 +905,7 @@ static struct sdw_driver max98373_sdw_driver = { .pm = &max98373_pm, }, .probe = max98373_sdw_probe, - .remove = NULL, + .remove = max98373_sdw_remove, .ops = &max98373_slave_ops, .id_table = max98373_id, }; diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index e14fe98349a5..f90a6a7ba83b 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -5,6 +5,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/cdev.h> @@ -436,12 +437,22 @@ const struct snd_soc_component_driver soc_codec_dev_max98373 = { .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(soc_codec_dev_max98373); +static int max98373_sdw_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { - .probe = NULL, + .probe = max98373_sdw_probe, .controls = max98373_snd_controls, .num_controls = ARRAY_SIZE(max98373_snd_controls), .dapm_widgets = max98373_dapm_widgets, @@ -450,7 +461,6 @@ const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw); diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index d1882cbc9381..7a5260ff8d6b 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -10,7 +10,7 @@ #include <linux/cdev.h> #include <linux/dmi.h> #include <linux/firmware.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of_gpio.h> @@ -161,8 +161,6 @@ static struct reg_default max98390_reg_defaults[] = { {MAX98390_R23FF_GLOBAL_EN, 0x00}, }; -static int max98390_dsm_calibrate(struct snd_soc_component *component); - static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; @@ -174,12 +172,12 @@ static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: mode = MAX98390_PCM_MASTER_MODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: - max98390->master = true; + case SND_SOC_DAIFMT_CBP_CFP: + max98390->provider = true; mode = MAX98390_PCM_MASTER_MODE_MASTER; break; default: @@ -265,7 +263,7 @@ static int max98390_set_clock(struct snd_soc_component *component, * snd_pcm_format_width(params_format(params)); int value; - if (max98390->master) { + if (max98390->provider) { int i; /* match rate to closest value */ for (i = 0; i < ARRAY_SIZE(rate_table); i++) { @@ -635,10 +633,48 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol, static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val; + + snd_soc_dapm_mutex_lock(dapm); + + regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val); + if (!val) { + /* Enable the codec for the duration of calibration readout */ + regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, + MAX98390_AMP_EN_MASK, 1); + regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, + MAX98390_GLOBAL_EN_MASK, 1); + } + + regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); + regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); + regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); + + if (!val) { + /* Disable the codec if it was disabled */ + regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, + MAX98390_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, + MAX98390_AMP_EN_MASK, 0); + } + + snd_soc_dapm_mutex_unlock(dapm); + + rdc_cal_result |= (rdc << 8) & 0x0000FFFF; + if (rdc_cal_result) + max98390->ref_rdc_value = 268435456U / rdc_cal_result; - max98390_dsm_calibrate(component); + max98390->ambient_temp_value = temp * 52 - 1188; + + rdc_integer = rdc_cal_result * 937 / 65536; + rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100); + + dev_info(component->dev, + "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", + rdc_integer, rdc_factor, rdc_cal_result, temp); return 0; } @@ -819,40 +855,6 @@ err: return ret; } -static int max98390_dsm_calibrate(struct snd_soc_component *component) -{ - unsigned int rdc, rdc_cal_result, temp; - unsigned int rdc_integer, rdc_factor; - struct max98390_priv *max98390 = - snd_soc_component_get_drvdata(component); - - regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x81); - regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x01); - - regmap_read(max98390->regmap, - THERMAL_RDC_RD_BACK_BYTE1, &rdc); - regmap_read(max98390->regmap, - THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); - rdc_cal_result |= (rdc << 8) & 0x0000FFFF; - if (rdc_cal_result) - max98390->ref_rdc_value = 268435456U / rdc_cal_result; - - regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); - max98390->ambient_temp_value = temp * 52 - 1188; - - rdc_integer = rdc_cal_result * 937 / 65536; - rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - - (rdc_integer * 100); - - dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", - rdc_integer, rdc_factor, rdc_cal_result, temp); - - regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x00); - regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); - - return 0; -} - static void max98390_init_regs(struct snd_soc_component *component) { struct max98390_priv *max98390 = @@ -983,7 +985,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98390 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98390_regmap = { @@ -1014,14 +1015,14 @@ static void max98390_slot_config(struct i2c_client *i2c, max98390->i_l_slot = 1; } -static int max98390_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98390_i2c_probe(struct i2c_client *i2c) { int ret = 0; int reg = 0; struct max98390_priv *max98390 = NULL; struct i2c_adapter *adapter = i2c->adapter; + struct gpio_desc *reset_gpio; ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE @@ -1073,6 +1074,17 @@ static int max98390_i2c_probe(struct i2c_client *i2c, return ret; } + reset_gpio = devm_gpiod_get_optional(&i2c->dev, + "reset", GPIOD_OUT_HIGH); + + /* Power on device */ + if (reset_gpio) { + usleep_range(1000, 2000); + /* bring out of reset */ + gpiod_set_value_cansleep(reset_gpio, 0); + usleep_range(1000, 2000); + } + /* Check Revision ID */ ret = regmap_read(max98390->regmap, MAX98390_R24FF_REV_ID, ®); @@ -1121,7 +1133,7 @@ static struct i2c_driver max98390_i2c_driver = { .acpi_match_table = ACPI_PTR(max98390_acpi_match), .pm = &max98390_pm, }, - .probe = max98390_i2c_probe, + .probe_new = max98390_i2c_probe, .id_table = max98390_i2c_id, }; diff --git a/sound/soc/codecs/max98390.h b/sound/soc/codecs/max98390.h index c250740f73a2..f4d6758ab4c6 100644 --- a/sound/soc/codecs/max98390.h +++ b/sound/soc/codecs/max98390.h @@ -656,7 +656,7 @@ struct max98390_priv { struct regmap *regmap; unsigned int sysclk; - unsigned int master; + unsigned int provider; unsigned int tdm_mode; unsigned int v_l_slot; unsigned int i_l_slot; diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c new file mode 100644 index 000000000000..a7b6a23f2cd8 --- /dev/null +++ b/sound/soc/codecs/max98396.c @@ -0,0 +1,1918 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022, Analog Devices Inc. + +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <sound/pcm_params.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> +#include <linux/gpio.h> +#include <sound/tlv.h> +#include "max98396.h" + +static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = { + "avdd", + "dvdd", + "dvddio", +}; + +static struct reg_default max98396_reg[] = { + {MAX98396_R2000_SW_RESET, 0x00}, + {MAX98396_R2001_INT_RAW1, 0x00}, + {MAX98396_R2002_INT_RAW2, 0x00}, + {MAX98396_R2003_INT_RAW3, 0x00}, + {MAX98396_R2004_INT_RAW4, 0x00}, + {MAX98396_R2006_INT_STATE1, 0x00}, + {MAX98396_R2007_INT_STATE2, 0x00}, + {MAX98396_R2008_INT_STATE3, 0x00}, + {MAX98396_R2009_INT_STATE4, 0x00}, + {MAX98396_R200B_INT_FLAG1, 0x00}, + {MAX98396_R200C_INT_FLAG2, 0x00}, + {MAX98396_R200D_INT_FLAG3, 0x00}, + {MAX98396_R200E_INT_FLAG4, 0x00}, + {MAX98396_R2010_INT_EN1, 0x02}, + {MAX98396_R2011_INT_EN2, 0x00}, + {MAX98396_R2012_INT_EN3, 0x00}, + {MAX98396_R2013_INT_EN4, 0x00}, + {MAX98396_R2015_INT_FLAG_CLR1, 0x00}, + {MAX98396_R2016_INT_FLAG_CLR2, 0x00}, + {MAX98396_R2017_INT_FLAG_CLR3, 0x00}, + {MAX98396_R2018_INT_FLAG_CLR4, 0x00}, + {MAX98396_R201F_IRQ_CTRL, 0x00}, + {MAX98396_R2020_THERM_WARN_THRESH, 0x46}, + {MAX98396_R2021_THERM_WARN_THRESH2, 0x46}, + {MAX98396_R2022_THERM_SHDN_THRESH, 0x64}, + {MAX98396_R2023_THERM_HYSTERESIS, 0x02}, + {MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5}, + {MAX98396_R2027_THERM_FOLDBACK_EN, 0x01}, + {MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32}, + {MAX98396_R2033_NOISEGATE_MODE_EN, 0x00}, + {MAX98396_R2038_CLK_MON_CTRL, 0x00}, + {MAX98396_R2039_DATA_MON_CTRL, 0x00}, + {MAX98396_R203F_ENABLE_CTRLS, 0x0F}, + {MAX98396_R2040_PIN_CFG, 0x55}, + {MAX98396_R2041_PCM_MODE_CFG, 0xC0}, + {MAX98396_R2042_PCM_CLK_SETUP, 0x04}, + {MAX98396_R2043_PCM_SR_SETUP, 0x88}, + {MAX98396_R2044_PCM_TX_CTRL_1, 0x00}, + {MAX98396_R2045_PCM_TX_CTRL_2, 0x00}, + {MAX98396_R2046_PCM_TX_CTRL_3, 0x00}, + {MAX98396_R2047_PCM_TX_CTRL_4, 0x00}, + {MAX98396_R2048_PCM_TX_CTRL_5, 0x00}, + {MAX98396_R2049_PCM_TX_CTRL_6, 0x00}, + {MAX98396_R204A_PCM_TX_CTRL_7, 0x00}, + {MAX98396_R204B_PCM_TX_CTRL_8, 0x00}, + {MAX98396_R204C_PCM_TX_HIZ_CTRL_1, 0xFF}, + {MAX98396_R204D_PCM_TX_HIZ_CTRL_2, 0xFF}, + {MAX98396_R204E_PCM_TX_HIZ_CTRL_3, 0xFF}, + {MAX98396_R204F_PCM_TX_HIZ_CTRL_4, 0xFF}, + {MAX98396_R2050_PCM_TX_HIZ_CTRL_5, 0xFF}, + {MAX98396_R2051_PCM_TX_HIZ_CTRL_6, 0xFF}, + {MAX98396_R2052_PCM_TX_HIZ_CTRL_7, 0xFF}, + {MAX98396_R2053_PCM_TX_HIZ_CTRL_8, 0xFF}, + {MAX98396_R2055_PCM_RX_SRC1, 0x00}, + {MAX98396_R2056_PCM_RX_SRC2, 0x00}, + {MAX98396_R2058_PCM_BYPASS_SRC, 0x00}, + {MAX98396_R205D_PCM_TX_SRC_EN, 0x00}, + {MAX98396_R205E_PCM_RX_EN, 0x00}, + {MAX98396_R205F_PCM_TX_EN, 0x00}, + {MAX98396_R2070_ICC_RX_EN_A, 0x00}, + {MAX98396_R2071_ICC_RX_EN_B, 0x00}, + {MAX98396_R2072_ICC_TX_CTRL, 0x00}, + {MAX98396_R207F_ICC_EN, 0x00}, + {MAX98396_R2083_TONE_GEN_DC_CFG, 0x04}, + {MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00}, + {MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00}, + {MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00}, + {MAX98396_R208F_TONE_GEN_EN, 0x00}, + {MAX98396_R2090_AMP_VOL_CTRL, 0x00}, + {MAX98396_R2091_AMP_PATH_GAIN, 0x0B}, + {MAX98396_R2092_AMP_DSP_CFG, 0x23}, + {MAX98396_R2093_SSM_CFG, 0x0D}, + {MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12}, + {MAX98396_R2095_SPK_CLS_DG_HDR, 0x17}, + {MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17}, + {MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00}, + {MAX98396_R2098_SPK_CLS_DG_MODE, 0x00}, + {MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03}, + {MAX98396_R209A_SPK_EDGE_CTRL, 0x00}, + {MAX98396_R209C_SPK_EDGE_CTRL1, 0x0A}, + {MAX98396_R209D_SPK_EDGE_CTRL2, 0xAA}, + {MAX98396_R209E_AMP_CLIP_GAIN, 0x00}, + {MAX98396_R209F_BYPASS_PATH_CFG, 0x00}, + {MAX98396_R20A0_AMP_SUPPLY_CTL, 0x00}, + {MAX98396_R20AF_AMP_EN, 0x00}, + {MAX98396_R20B0_ADC_SR, 0x30}, + {MAX98396_R20B1_ADC_PVDD_CFG, 0x00}, + {MAX98396_R20B2_ADC_VBAT_CFG, 0x00}, + {MAX98396_R20B3_ADC_THERMAL_CFG, 0x00}, + {MAX98396_R20B4_ADC_READBACK_CTRL1, 0x00}, + {MAX98396_R20B5_ADC_READBACK_CTRL2, 0x00}, + {MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0x00}, + {MAX98396_R20B7_ADC_PVDD_READBACK_LSB, 0x00}, + {MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0x00}, + {MAX98396_R20B9_ADC_VBAT_READBACK_LSB, 0x00}, + {MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0x00}, + {MAX98396_R20BB_ADC_TEMP_READBACK_LSB, 0x00}, + {MAX98396_R20BC_ADC_LO_PVDD_READBACK_MSB, 0x00}, + {MAX98396_R20BD_ADC_LO_PVDD_READBACK_LSB, 0x00}, + {MAX98396_R20BE_ADC_LO_VBAT_READBACK_MSB, 0x00}, + {MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00}, + {MAX98396_R20C7_ADC_CFG, 0x00}, + {MAX98396_R20D0_DHT_CFG1, 0x00}, + {MAX98396_R20D1_LIMITER_CFG1, 0x08}, + {MAX98396_R20D2_LIMITER_CFG2, 0x00}, + {MAX98396_R20D3_DHT_CFG2, 0x14}, + {MAX98396_R20D4_DHT_CFG3, 0x02}, + {MAX98396_R20D5_DHT_CFG4, 0x04}, + {MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07}, + {MAX98396_R20DF_DHT_EN, 0x00}, + {MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04}, + {MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00}, + {MAX98396_R20E5_BPE_STATE, 0x00}, + {MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00}, + {MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00}, + {MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00}, + {MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00}, + {MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00}, + {MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00}, + {MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00}, + {MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00}, + {MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00}, + {MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00}, + {MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00}, + {MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00}, + {MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00}, + {MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00}, + {MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00}, + {MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00}, + {MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00}, + {MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00}, + {MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00}, + {MAX98396_R2108_BPE_SUPPLY_SRC, 0x00}, + {MAX98396_R2109_BPE_LOW_STATE, 0x00}, + {MAX98396_R210A_BPE_LOW_GAIN, 0x00}, + {MAX98396_R210B_BPE_LOW_LIMITER, 0x00}, + {MAX98396_R210D_BPE_EN, 0x00}, + {MAX98396_R210E_AUTO_RESTART, 0x00}, + {MAX98396_R210F_GLOBAL_EN, 0x00}, + {MAX98396_R21FF_REVISION_ID, 0x00}, +}; + +static struct reg_default max98397_reg[] = { + {MAX98396_R2000_SW_RESET, 0x00}, + {MAX98396_R2001_INT_RAW1, 0x00}, + {MAX98396_R2002_INT_RAW2, 0x00}, + {MAX98396_R2003_INT_RAW3, 0x00}, + {MAX98396_R2004_INT_RAW4, 0x00}, + {MAX98396_R2006_INT_STATE1, 0x00}, + {MAX98396_R2007_INT_STATE2, 0x00}, + {MAX98396_R2008_INT_STATE3, 0x00}, + {MAX98396_R2009_INT_STATE4, 0x00}, + {MAX98396_R200B_INT_FLAG1, 0x00}, + {MAX98396_R200C_INT_FLAG2, 0x00}, + {MAX98396_R200D_INT_FLAG3, 0x00}, + {MAX98396_R200E_INT_FLAG4, 0x00}, + {MAX98396_R2010_INT_EN1, 0x02}, + {MAX98396_R2011_INT_EN2, 0x00}, + {MAX98396_R2012_INT_EN3, 0x00}, + {MAX98396_R2013_INT_EN4, 0x00}, + {MAX98396_R2015_INT_FLAG_CLR1, 0x00}, + {MAX98396_R2016_INT_FLAG_CLR2, 0x00}, + {MAX98396_R2017_INT_FLAG_CLR3, 0x00}, + {MAX98396_R2018_INT_FLAG_CLR4, 0x00}, + {MAX98396_R201F_IRQ_CTRL, 0x00}, + {MAX98396_R2020_THERM_WARN_THRESH, 0x46}, + {MAX98396_R2021_THERM_WARN_THRESH2, 0x46}, + {MAX98396_R2022_THERM_SHDN_THRESH, 0x64}, + {MAX98396_R2023_THERM_HYSTERESIS, 0x02}, + {MAX98396_R2024_THERM_FOLDBACK_SET, 0xC5}, + {MAX98396_R2027_THERM_FOLDBACK_EN, 0x01}, + {MAX98396_R2030_NOISEGATE_MODE_CTRL, 0x32}, + {MAX98396_R2033_NOISEGATE_MODE_EN, 0x00}, + {MAX98396_R2038_CLK_MON_CTRL, 0x00}, + {MAX98396_R2039_DATA_MON_CTRL, 0x00}, + {MAX98397_R203A_SPK_MON_THRESH, 0x03}, + {MAX98396_R203F_ENABLE_CTRLS, 0x0F}, + {MAX98396_R2040_PIN_CFG, 0x55}, + {MAX98396_R2041_PCM_MODE_CFG, 0xC0}, + {MAX98396_R2042_PCM_CLK_SETUP, 0x04}, + {MAX98396_R2043_PCM_SR_SETUP, 0x88}, + {MAX98396_R2044_PCM_TX_CTRL_1, 0x00}, + {MAX98396_R2045_PCM_TX_CTRL_2, 0x00}, + {MAX98396_R2046_PCM_TX_CTRL_3, 0x00}, + {MAX98396_R2047_PCM_TX_CTRL_4, 0x00}, + {MAX98396_R2048_PCM_TX_CTRL_5, 0x00}, + {MAX98396_R2049_PCM_TX_CTRL_6, 0x00}, + {MAX98396_R204A_PCM_TX_CTRL_7, 0x00}, + {MAX98396_R204B_PCM_TX_CTRL_8, 0x00}, + {MAX98397_R204C_PCM_TX_CTRL_9, 0x00}, + {MAX98397_R204D_PCM_TX_HIZ_CTRL_1, 0xFF}, + {MAX98397_R204E_PCM_TX_HIZ_CTRL_2, 0xFF}, + {MAX98397_R204F_PCM_TX_HIZ_CTRL_3, 0xFF}, + {MAX98397_R2050_PCM_TX_HIZ_CTRL_4, 0xFF}, + {MAX98397_R2051_PCM_TX_HIZ_CTRL_5, 0xFF}, + {MAX98397_R2052_PCM_TX_HIZ_CTRL_6, 0xFF}, + {MAX98397_R2053_PCM_TX_HIZ_CTRL_7, 0xFF}, + {MAX98397_R2054_PCM_TX_HIZ_CTRL_8, 0xFF}, + {MAX98397_R2056_PCM_RX_SRC1, 0x00}, + {MAX98397_R2057_PCM_RX_SRC2, 0x00}, + {MAX98396_R2058_PCM_BYPASS_SRC, 0x00}, + {MAX98396_R205D_PCM_TX_SRC_EN, 0x00}, + {MAX98396_R205E_PCM_RX_EN, 0x00}, + {MAX98396_R205F_PCM_TX_EN, 0x00}, + {MAX98397_R2060_PCM_TX_SUPPLY_SEL, 0x00}, + {MAX98396_R2070_ICC_RX_EN_A, 0x00}, + {MAX98396_R2071_ICC_RX_EN_B, 0x00}, + {MAX98396_R2072_ICC_TX_CTRL, 0x00}, + {MAX98396_R207F_ICC_EN, 0x00}, + {MAX98396_R2083_TONE_GEN_DC_CFG, 0x04}, + {MAX98396_R2084_TONE_GEN_DC_LVL1, 0x00}, + {MAX98396_R2085_TONE_GEN_DC_LVL2, 0x00}, + {MAX98396_R2086_TONE_GEN_DC_LVL3, 0x00}, + {MAX98396_R208F_TONE_GEN_EN, 0x00}, + {MAX98396_R2090_AMP_VOL_CTRL, 0x00}, + {MAX98396_R2091_AMP_PATH_GAIN, 0x12}, + {MAX98396_R2092_AMP_DSP_CFG, 0x22}, + {MAX98396_R2093_SSM_CFG, 0x08}, + {MAX98396_R2094_SPK_CLS_DG_THRESH, 0x12}, + {MAX98396_R2095_SPK_CLS_DG_HDR, 0x17}, + {MAX98396_R2096_SPK_CLS_DG_HOLD_TIME, 0x17}, + {MAX98396_R2097_SPK_CLS_DG_DELAY, 0x00}, + {MAX98396_R2098_SPK_CLS_DG_MODE, 0x00}, + {MAX98396_R2099_SPK_CLS_DG_VBAT_LVL, 0x03}, + {MAX98396_R209A_SPK_EDGE_CTRL, 0x00}, + {MAX98397_R209B_SPK_PATH_WB_ONLY, 0x00}, + {MAX98396_R209C_SPK_EDGE_CTRL1, 0x03}, + {MAX98396_R209D_SPK_EDGE_CTRL2, 0xFC}, + {MAX98396_R209E_AMP_CLIP_GAIN, 0x00}, + {MAX98396_R209F_BYPASS_PATH_CFG, 0x00}, + {MAX98396_R20AF_AMP_EN, 0x00}, + {MAX98396_R20B0_ADC_SR, 0x30}, + {MAX98396_R20B1_ADC_PVDD_CFG, 0x00}, + {MAX98396_R20B2_ADC_VBAT_CFG, 0x00}, + {MAX98396_R20B3_ADC_THERMAL_CFG, 0x00}, + {MAX98397_R20B4_ADC_VDDH_CFG, 0x00}, + {MAX98397_R20B5_ADC_READBACK_CTRL1, 0x00}, + {MAX98397_R20B6_ADC_READBACK_CTRL2, 0x00}, + {MAX98397_R20B7_ADC_PVDD_READBACK_MSB, 0x00}, + {MAX98397_R20B8_ADC_PVDD_READBACK_LSB, 0x00}, + {MAX98397_R20B9_ADC_VBAT_READBACK_MSB, 0x00}, + {MAX98397_R20BA_ADC_VBAT_READBACK_LSB, 0x00}, + {MAX98397_R20BB_ADC_TEMP_READBACK_MSB, 0x00}, + {MAX98397_R20BC_ADC_TEMP_READBACK_LSB, 0x00}, + {MAX98397_R20BD_ADC_VDDH__READBACK_MSB, 0x00}, + {MAX98397_R20BE_ADC_VDDH_READBACK_LSB, 0x00}, + {MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB, 0x00}, + {MAX98397_R20C3_ADC_LO_VDDH_READBACK_MSB, 0x00}, + {MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB, 0x00}, + {MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE, 0x04}, + {MAX98396_R20C7_ADC_CFG, 0x00}, + {MAX98396_R20D0_DHT_CFG1, 0x00}, + {MAX98396_R20D1_LIMITER_CFG1, 0x08}, + {MAX98396_R20D2_LIMITER_CFG2, 0x00}, + {MAX98396_R20D3_DHT_CFG2, 0x14}, + {MAX98396_R20D4_DHT_CFG3, 0x02}, + {MAX98396_R20D5_DHT_CFG4, 0x04}, + {MAX98396_R20D6_DHT_HYSTERESIS_CFG, 0x07}, + {MAX98396_R20DF_DHT_EN, 0x00}, + {MAX98396_R20E0_IV_SENSE_PATH_CFG, 0x04}, + {MAX98396_R20E4_IV_SENSE_PATH_EN, 0x00}, + {MAX98396_R20E5_BPE_STATE, 0x00}, + {MAX98396_R20E6_BPE_L3_THRESH_MSB, 0x00}, + {MAX98396_R20E7_BPE_L3_THRESH_LSB, 0x00}, + {MAX98396_R20E8_BPE_L2_THRESH_MSB, 0x00}, + {MAX98396_R20E9_BPE_L2_THRESH_LSB, 0x00}, + {MAX98396_R20EA_BPE_L1_THRESH_MSB, 0x00}, + {MAX98396_R20EB_BPE_L1_THRESH_LSB, 0x00}, + {MAX98396_R20EC_BPE_L0_THRESH_MSB, 0x00}, + {MAX98396_R20ED_BPE_L0_THRESH_LSB, 0x00}, + {MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME, 0x00}, + {MAX98396_R20F1_BPE_L0_HOLD_TIME, 0x00}, + {MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP, 0x00}, + {MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN, 0x00}, + {MAX98396_R20FA_BPE_L3_ATT_REL_RATE, 0x00}, + {MAX98396_R20FB_BPE_L2_ATT_REL_RATE, 0x00}, + {MAX98396_R20FC_BPE_L1_ATT_REL_RATE, 0x00}, + {MAX98396_R20FD_BPE_L0_ATT_REL_RATE, 0x00}, + {MAX98396_R20FE_BPE_L3_LIMITER_CFG, 0x00}, + {MAX98396_R20FF_BPE_L2_LIMITER_CFG, 0x00}, + {MAX98396_R2100_BPE_L1_LIMITER_CFG, 0x00}, + {MAX98396_R2101_BPE_L0_LIMITER_CFG, 0x00}, + {MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE, 0x00}, + {MAX98396_R2106_BPE_THRESH_HYSTERESIS, 0x00}, + {MAX98396_R2107_BPE_INFINITE_HOLD_CLR, 0x00}, + {MAX98396_R2108_BPE_SUPPLY_SRC, 0x00}, + {MAX98396_R2109_BPE_LOW_STATE, 0x00}, + {MAX98396_R210A_BPE_LOW_GAIN, 0x00}, + {MAX98396_R210B_BPE_LOW_LIMITER, 0x00}, + {MAX98396_R210D_BPE_EN, 0x00}, + {MAX98396_R210E_AUTO_RESTART, 0x00}, + {MAX98396_R210F_GLOBAL_EN, 0x00}, + {MAX98397_R22FF_REVISION_ID, 0x00}, +}; + +static void max98396_global_enable_onoff(struct regmap *regmap, bool onoff) +{ + regmap_write(regmap, MAX98396_R210F_GLOBAL_EN, onoff ? 1 : 0); + usleep_range(11000, 12000); +} + +static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); + unsigned int format_mask, format = 0; + unsigned int bclk_pol = 0; + int ret, status; + int reg; + bool update = false; + + format_mask = MAX98396_PCM_MODE_CFG_FORMAT_MASK | + MAX98396_PCM_MODE_CFG_LRCLKEDGE; + + dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + format = MAX98396_PCM_MODE_CFG_LRCLKEDGE; + break; + case SND_SOC_DAIFMT_IB_NF: + bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE; + break; + case SND_SOC_DAIFMT_IB_IF: + bclk_pol = MAX98396_PCM_MODE_CFG_BCLKEDGE; + format = MAX98396_PCM_MODE_CFG_LRCLKEDGE; + break; + + default: + dev_err(component->dev, "DAI invert mode %d unsupported\n", + fmt & SND_SOC_DAIFMT_INV_MASK); + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format |= MAX98396_PCM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + format |= MAX98396_PCM_FORMAT_LJ; + break; + case SND_SOC_DAIFMT_DSP_A: + format |= MAX98396_PCM_FORMAT_TDM_MODE1; + break; + case SND_SOC_DAIFMT_DSP_B: + format |= MAX98396_PCM_FORMAT_TDM_MODE0; + break; + default: + dev_err(component->dev, "DAI format %d unsupported\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); + if (ret < 0) + return -EINVAL; + + if (status) { + ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); + if (ret < 0) + return -EINVAL; + if (format != (reg & format_mask)) { + update = true; + } else { + ret = regmap_read(max98396->regmap, + MAX98396_R2042_PCM_CLK_SETUP, ®); + if (ret < 0) + return -EINVAL; + if (bclk_pol != (reg & MAX98396_PCM_MODE_CFG_BCLKEDGE)) + update = true; + } + /* GLOBAL_EN OFF prior to pcm mode, clock configuration change */ + if (update) + max98396_global_enable_onoff(max98396->regmap, false); + } + + regmap_update_bits(max98396->regmap, + MAX98396_R2041_PCM_MODE_CFG, + format_mask, format); + + regmap_update_bits(max98396->regmap, + MAX98396_R2042_PCM_CLK_SETUP, + MAX98396_PCM_MODE_CFG_BCLKEDGE, + bclk_pol); + + if (status && update) + max98396_global_enable_onoff(max98396->regmap, true); + + return 0; +} + +#define MAX98396_BSEL_32 0x2 +#define MAX98396_BSEL_48 0x3 +#define MAX98396_BSEL_64 0x4 +#define MAX98396_BSEL_96 0x5 +#define MAX98396_BSEL_128 0x6 +#define MAX98396_BSEL_192 0x7 +#define MAX98396_BSEL_256 0x8 +#define MAX98396_BSEL_384 0x9 +#define MAX98396_BSEL_512 0xa +#define MAX98396_BSEL_320 0xb +#define MAX98396_BSEL_250 0xc +#define MAX98396_BSEL_125 0xd + +/* Refer to table 5 in the datasheet */ +static const struct max98396_pcm_config { + int in, out, width, bsel, max_sr; +} max98396_pcm_configs[] = { + { .in = 2, .out = 4, .width = 16, .bsel = MAX98396_BSEL_32, .max_sr = 192000 }, + { .in = 2, .out = 6, .width = 24, .bsel = MAX98396_BSEL_48, .max_sr = 192000 }, + { .in = 2, .out = 8, .width = 32, .bsel = MAX98396_BSEL_64, .max_sr = 192000 }, + { .in = 3, .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, + { .in = 4, .out = 8, .width = 16, .bsel = MAX98396_BSEL_64, .max_sr = 192000 }, + { .in = 4, .out = 12, .width = 24, .bsel = MAX98396_BSEL_96, .max_sr = 192000 }, + { .in = 4, .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 192000 }, + { .in = 5, .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, + { .in = 7, .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 192000 }, + { .in = 2, .out = 4, .width = 16, .bsel = MAX98396_BSEL_32, .max_sr = 96000 }, + { .in = 2, .out = 6, .width = 24, .bsel = MAX98396_BSEL_48, .max_sr = 96000 }, + { .in = 2, .out = 8, .width = 32, .bsel = MAX98396_BSEL_64, .max_sr = 96000 }, + { .in = 3, .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, + { .in = 4, .out = 8, .width = 16, .bsel = MAX98396_BSEL_64, .max_sr = 96000 }, + { .in = 4, .out = 12, .width = 24, .bsel = MAX98396_BSEL_96, .max_sr = 96000 }, + { .in = 4, .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 96000 }, + { .in = 5, .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, + { .in = 7, .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 96000 }, + { .in = 7, .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, + { .in = 8, .out = 16, .width = 16, .bsel = MAX98396_BSEL_128, .max_sr = 96000 }, + { .in = 8, .out = 24, .width = 24, .bsel = MAX98396_BSEL_192, .max_sr = 96000 }, + { .in = 8, .out = 32, .width = 32, .bsel = MAX98396_BSEL_256, .max_sr = 96000 }, + { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, + { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 96000 }, + { .in = 16, .out = 32, .width = 16, .bsel = MAX98396_BSEL_256, .max_sr = 96000 }, + { .in = 7, .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, + { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, + { .in = 10, .out = 40, .width = 32, .bsel = MAX98396_BSEL_320, .max_sr = 48000 }, + { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 48000 }, + { .in = 16, .out = 48, .width = 24, .bsel = MAX98396_BSEL_384, .max_sr = 48000 }, + { .in = 16, .out = 64, .width = 32, .bsel = MAX98396_BSEL_512, .max_sr = 48000 }, +}; + +static int max98396_pcm_config_index(int in_slots, int out_slots, int width) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(max98396_pcm_configs); i++) { + const struct max98396_pcm_config *c = &max98396_pcm_configs[i]; + + if (in_slots == c->in && out_slots <= c->out && width == c->width) + return i; + } + + return -1; +} + +static int max98396_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); + unsigned int sampling_rate = 0; + unsigned int chan_sz = 0; + int ret, reg, status, bsel = 0; + bool update = false; + + /* pcm mode configuration */ + switch (snd_pcm_format_width(params_format(params))) { + case 16: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16; + break; + case 24: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24; + break; + case 32: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32; + break; + default: + dev_err(component->dev, "format unsupported %d\n", + params_format(params)); + goto err; + } + + dev_dbg(component->dev, "format supported %d", + params_format(params)); + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 8000: + sampling_rate = MAX98396_PCM_SR_8000; + break; + case 11025: + sampling_rate = MAX98396_PCM_SR_11025; + break; + case 12000: + sampling_rate = MAX98396_PCM_SR_12000; + break; + case 16000: + sampling_rate = MAX98396_PCM_SR_16000; + break; + case 22050: + sampling_rate = MAX98396_PCM_SR_22050; + break; + case 24000: + sampling_rate = MAX98396_PCM_SR_24000; + break; + case 32000: + sampling_rate = MAX98396_PCM_SR_32000; + break; + case 44100: + sampling_rate = MAX98396_PCM_SR_44100; + break; + case 48000: + sampling_rate = MAX98396_PCM_SR_48000; + break; + case 88200: + sampling_rate = MAX98396_PCM_SR_88200; + break; + case 96000: + sampling_rate = MAX98396_PCM_SR_96000; + break; + case 192000: + sampling_rate = MAX98396_PCM_SR_192000; + break; + default: + dev_err(component->dev, "rate %d not supported\n", + params_rate(params)); + goto err; + } + + if (max98396->tdm_mode) { + if (params_rate(params) > max98396->tdm_max_samplerate) { + dev_err(component->dev, "TDM sample rate %d too high", + params_rate(params)); + goto err; + } + } else { + /* BCLK configuration */ + ret = max98396_pcm_config_index(params_channels(params), + params_channels(params), + snd_pcm_format_width(params_format(params))); + if (ret < 0) { + dev_err(component->dev, + "no PCM config for %d channels, format %d\n", + params_channels(params), params_format(params)); + goto err; + } + + bsel = max98396_pcm_configs[ret].bsel; + + if (params_rate(params) > max98396_pcm_configs[ret].max_sr) { + dev_err(component->dev, "sample rate %d too high", + params_rate(params)); + goto err; + } + } + + ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); + if (ret < 0) + goto err; + + if (status) { + ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); + if (ret < 0) + goto err; + if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK)) { + update = true; + } else { + ret = regmap_read(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP, ®); + if (ret < 0) + goto err; + if (sampling_rate != (reg & MAX98396_PCM_SR_MASK)) + update = true; + } + + /* GLOBAL_EN OFF prior to channel size and sampling rate change */ + if (update) + max98396_global_enable_onoff(max98396->regmap, false); + } + + /* set channel size */ + regmap_update_bits(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, + MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98396->regmap, MAX98396_R2043_PCM_SR_SETUP, + MAX98396_PCM_SR_MASK, sampling_rate); + + /* set sampling rate of IV */ + if (max98396->interleave_mode && + sampling_rate > MAX98396_PCM_SR_16000) + regmap_update_bits(max98396->regmap, + MAX98396_R2043_PCM_SR_SETUP, + MAX98396_IVADC_SR_MASK, + (sampling_rate - 3) + << MAX98396_IVADC_SR_SHIFT); + else + regmap_update_bits(max98396->regmap, + MAX98396_R2043_PCM_SR_SETUP, + MAX98396_IVADC_SR_MASK, + sampling_rate << MAX98396_IVADC_SR_SHIFT); + + if (bsel) + regmap_update_bits(max98396->regmap, + MAX98396_R2042_PCM_CLK_SETUP, + MAX98396_PCM_CLK_SETUP_BSEL_MASK, + bsel); + + if (status && update) + max98396_global_enable_onoff(max98396->regmap, true); + + return 0; + +err: + return -EINVAL; +} + +static int max98396_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct max98396_priv *max98396 = + snd_soc_component_get_drvdata(component); + int bsel; + unsigned int chan_sz = 0; + int ret, status; + int reg; + bool update = false; + + if (!tx_mask && !rx_mask && !slots && !slot_width) + max98396->tdm_mode = false; + else + max98396->tdm_mode = true; + + /* BCLK configuration */ + ret = max98396_pcm_config_index(slots, slots, slot_width); + if (ret < 0) { + dev_err(component->dev, "no TDM config for %d slots %d bits\n", + slots, slot_width); + return -EINVAL; + } + + bsel = max98396_pcm_configs[ret].bsel; + max98396->tdm_max_samplerate = max98396_pcm_configs[ret].max_sr; + + /* Channel size configuration */ + switch (slot_width) { + case 16: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_16; + break; + case 24: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_24; + break; + case 32: + chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32; + break; + default: + dev_err(component->dev, "slot width %d unsupported\n", + slot_width); + return -EINVAL; + } + + ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); + if (ret < 0) + return -EINVAL; + + if (status) { + ret = regmap_read(max98396->regmap, MAX98396_R2042_PCM_CLK_SETUP, ®); + if (ret < 0) + return -EINVAL; + if (bsel != (reg & MAX98396_PCM_CLK_SETUP_BSEL_MASK)) { + update = true; + } else { + ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, ®); + if (ret < 0) + return -EINVAL; + if (chan_sz != (reg & MAX98396_PCM_MODE_CFG_CHANSZ_MASK)) + update = true; + } + + /* GLOBAL_EN OFF prior to channel size and BCLK per LRCLK change */ + if (update) + max98396_global_enable_onoff(max98396->regmap, false); + } + + regmap_update_bits(max98396->regmap, + MAX98396_R2042_PCM_CLK_SETUP, + MAX98396_PCM_CLK_SETUP_BSEL_MASK, + bsel); + + regmap_update_bits(max98396->regmap, + MAX98396_R2041_PCM_MODE_CFG, + MAX98396_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + + /* Rx slot configuration */ + if (max98396->device_id == CODEC_TYPE_MAX98396) { + regmap_update_bits(max98396->regmap, + MAX98396_R2056_PCM_RX_SRC2, + MAX98396_PCM_DMIX_CH0_SRC_MASK, + rx_mask); + regmap_update_bits(max98396->regmap, + MAX98396_R2056_PCM_RX_SRC2, + MAX98396_PCM_DMIX_CH1_SRC_MASK, + rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT); + } else { + regmap_update_bits(max98396->regmap, + MAX98397_R2057_PCM_RX_SRC2, + MAX98396_PCM_DMIX_CH0_SRC_MASK, + rx_mask); + regmap_update_bits(max98396->regmap, + MAX98397_R2057_PCM_RX_SRC2, + MAX98396_PCM_DMIX_CH1_SRC_MASK, + rx_mask << MAX98396_PCM_DMIX_CH1_SHIFT); + } + + /* Tx slot Hi-Z configuration */ + if (max98396->device_id == CODEC_TYPE_MAX98396) { + regmap_write(max98396->regmap, + MAX98396_R2053_PCM_TX_HIZ_CTRL_8, + ~tx_mask & 0xFF); + regmap_write(max98396->regmap, + MAX98396_R2052_PCM_TX_HIZ_CTRL_7, + (~tx_mask & 0xFF00) >> 8); + } else { + regmap_write(max98396->regmap, + MAX98397_R2054_PCM_TX_HIZ_CTRL_8, + ~tx_mask & 0xFF); + regmap_write(max98396->regmap, + MAX98397_R2053_PCM_TX_HIZ_CTRL_7, + (~tx_mask & 0xFF00) >> 8); + } + + if (status && update) + max98396_global_enable_onoff(max98396->regmap, true); + + return 0; +} + +#define MAX98396_RATES SNDRV_PCM_RATE_8000_192000 + +#define MAX98396_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops max98396_dai_ops = { + .set_fmt = max98396_dai_set_fmt, + .hw_params = max98396_dai_hw_params, + .set_tdm_slot = max98396_dai_tdm_slot, +}; + +static int max98396_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct max98396_priv *max98396 = + snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + max98396_global_enable_onoff(max98396->regmap, true); + break; + case SND_SOC_DAPM_PRE_PMD: + max98396_global_enable_onoff(max98396->regmap, false); + + max98396->tdm_mode = false; + break; + default: + return 0; + } + return 0; +} + +static bool max98396_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4: + case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4: + case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4: + case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4: + case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4: + case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET: + case MAX98396_R2027_THERM_FOLDBACK_EN: + case MAX98396_R2030_NOISEGATE_MODE_CTRL: + case MAX98396_R2033_NOISEGATE_MODE_EN: + case MAX98396_R2038_CLK_MON_CTRL ... MAX98396_R2039_DATA_MON_CTRL: + case MAX98396_R203F_ENABLE_CTRLS ... MAX98396_R2053_PCM_TX_HIZ_CTRL_8: + case MAX98396_R2055_PCM_RX_SRC1 ... MAX98396_R2056_PCM_RX_SRC2: + case MAX98396_R2058_PCM_BYPASS_SRC: + case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98396_R205F_PCM_TX_EN: + case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL: + case MAX98396_R207F_ICC_EN: + case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3: + case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209A_SPK_EDGE_CTRL: + case MAX98396_R209C_SPK_EDGE_CTRL1 ... MAX98396_R20A0_AMP_SUPPLY_CTL: + case MAX98396_R20AF_AMP_EN ... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB: + case MAX98396_R20C7_ADC_CFG: + case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG: + case MAX98396_R20DF_DHT_EN: + case MAX98396_R20E0_IV_SENSE_PATH_CFG: + case MAX98396_R20E4_IV_SENSE_PATH_EN + ... MAX98396_R2106_BPE_THRESH_HYSTERESIS: + case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER: + case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN: + case MAX98396_R21FF_REVISION_ID: + return true; + default: + return false; + } +}; + +static bool max98396_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98396_R2000_SW_RESET: + case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4: + case MAX98396_R2041_PCM_MODE_CFG: + case MAX98396_R20B6_ADC_PVDD_READBACK_MSB + ... MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB: + case MAX98396_R20E5_BPE_STATE: + case MAX98396_R2109_BPE_LOW_STATE + ... MAX98396_R210B_BPE_LOW_LIMITER: + case MAX98396_R210F_GLOBAL_EN: + case MAX98396_R21FF_REVISION_ID: + return true; + default: + return false; + } +} + +static bool max98397_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98396_R2001_INT_RAW1 ... MAX98396_R2004_INT_RAW4: + case MAX98396_R2006_INT_STATE1 ... MAX98396_R2009_INT_STATE4: + case MAX98396_R200B_INT_FLAG1 ... MAX98396_R200E_INT_FLAG4: + case MAX98396_R2010_INT_EN1 ... MAX98396_R2013_INT_EN4: + case MAX98396_R2015_INT_FLAG_CLR1 ... MAX98396_R2018_INT_FLAG_CLR4: + case MAX98396_R201F_IRQ_CTRL ... MAX98396_R2024_THERM_FOLDBACK_SET: + case MAX98396_R2027_THERM_FOLDBACK_EN: + case MAX98396_R2030_NOISEGATE_MODE_CTRL: + case MAX98396_R2033_NOISEGATE_MODE_EN: + case MAX98396_R2038_CLK_MON_CTRL ... MAX98397_R203A_SPK_MON_THRESH: + case MAX98396_R203F_ENABLE_CTRLS ... MAX98397_R2054_PCM_TX_HIZ_CTRL_8: + case MAX98397_R2056_PCM_RX_SRC1... MAX98396_R2058_PCM_BYPASS_SRC: + case MAX98396_R205D_PCM_TX_SRC_EN ... MAX98397_R2060_PCM_TX_SUPPLY_SEL: + case MAX98396_R2070_ICC_RX_EN_A... MAX98396_R2072_ICC_TX_CTRL: + case MAX98396_R207F_ICC_EN: + case MAX98396_R2083_TONE_GEN_DC_CFG ... MAX98396_R2086_TONE_GEN_DC_LVL3: + case MAX98396_R208F_TONE_GEN_EN ... MAX98396_R209F_BYPASS_PATH_CFG: + case MAX98396_R20AF_AMP_EN ... MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE: + case MAX98396_R20C7_ADC_CFG: + case MAX98396_R20D0_DHT_CFG1 ... MAX98396_R20D6_DHT_HYSTERESIS_CFG: + case MAX98396_R20DF_DHT_EN: + case MAX98396_R20E0_IV_SENSE_PATH_CFG: + case MAX98396_R20E4_IV_SENSE_PATH_EN + ... MAX98396_R2106_BPE_THRESH_HYSTERESIS: + case MAX98396_R2108_BPE_SUPPLY_SRC ... MAX98396_R210B_BPE_LOW_LIMITER: + case MAX98396_R210D_BPE_EN ... MAX98396_R210F_GLOBAL_EN: + case MAX98397_R22FF_REVISION_ID: + return true; + default: + return false; + } +}; + +static bool max98397_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98396_R2001_INT_RAW1 ... MAX98396_R200E_INT_FLAG4: + case MAX98396_R2041_PCM_MODE_CFG: + case MAX98397_R20B7_ADC_PVDD_READBACK_MSB + ... MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB: + case MAX98396_R20E5_BPE_STATE: + case MAX98396_R2109_BPE_LOW_STATE + ... MAX98396_R210B_BPE_LOW_LIMITER: + case MAX98396_R210F_GLOBAL_EN: + case MAX98397_R22FF_REVISION_ID: + return true; + default: + return false; + } +} + +static const char * const max98396_op_mod_text[] = { + "DG", "PVDD", "VBAT", +}; + +static SOC_ENUM_SINGLE_DECL(max98396_op_mod_enum, + MAX98396_R2098_SPK_CLS_DG_MODE, + 0, max98396_op_mod_text); + +static DECLARE_TLV_DB_SCALE(max98396_digital_tlv, -6350, 50, 1); +static const DECLARE_TLV_DB_RANGE(max98396_spk_tlv, + 0, 0x11, TLV_DB_SCALE_ITEM(400, 100, 0), +); +static DECLARE_TLV_DB_RANGE(max98397_digital_tlv, + 0, 0x4A, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 0x4B, 0xFF, TLV_DB_SCALE_ITEM(-9000, 50, 0), +); +static const DECLARE_TLV_DB_RANGE(max98397_spk_tlv, + 0, 0x15, TLV_DB_SCALE_ITEM(600, 100, 0), +); + +static int max98396_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); + int reg, val; + + if (max98396->device_id == CODEC_TYPE_MAX98396) + reg = MAX98396_R2055_PCM_RX_SRC1; + else + reg = MAX98397_R2056_PCM_RX_SRC1; + + regmap_read(max98396->regmap, reg, &val); + + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int max98396_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + int reg, val; + int change; + + if (item[0] >= e->items) + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + if (max98396->device_id == CODEC_TYPE_MAX98396) + reg = MAX98396_R2055_PCM_RX_SRC1; + else + reg = MAX98397_R2056_PCM_RX_SRC1; + + change = snd_soc_component_test_bits(component, reg, + MAX98396_PCM_RX_MASK, val); + + if (change) + regmap_update_bits(max98396->regmap, reg, + MAX98396_PCM_RX_MASK, val); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); + + return change; +} + +static const char * const max98396_switch_text[] = { + "Left", "Right", "LeftRight"}; + +static SOC_ENUM_SINGLE_DECL(dai_sel_enum, SND_SOC_NOPM, 0, + max98396_switch_text); + +static const struct snd_kcontrol_new max98396_dai_mux = + SOC_DAPM_ENUM_EXT("DAI Sel Mux", dai_sel_enum, + max98396_mux_get, max98396_mux_put); + +static const struct snd_kcontrol_new max98396_vi_control = + SOC_DAPM_SINGLE("Switch", MAX98396_R205F_PCM_TX_EN, 0, 1, 0); + +static const struct snd_soc_dapm_widget max98396_dapm_widgets[] = { + SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", + MAX98396_R20AF_AMP_EN, 0, 0, max98396_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, + &max98396_dai_mux), + SND_SOC_DAPM_OUTPUT("BE_OUT"), + SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, + MAX98396_R20E4_IV_SENSE_PATH_EN, 0, 0), + SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, + MAX98396_R20E4_IV_SENSE_PATH_EN, 1, 0), + SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, + &max98396_vi_control), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON"), + SND_SOC_DAPM_SIGGEN("FBMON"), +}; + +static const char * const max98396_thermal_thresh_text[] = { + "50C", "51C", "52C", "53C", "54C", "55C", "56C", "57C", + "58C", "59C", "60C", "61C", "62C", "63C", "64C", "65C", + "66C", "67C", "68C", "69C", "70C", "71C", "72C", "73C", + "74C", "75C", "76C", "77C", "78C", "79C", "80C", "81C", + "82C", "83C", "84C", "85C", "86C", "87C", "88C", "89C", + "90C", "91C", "92C", "93C", "94C", "95C", "96C", "97C", + "98C", "99C", "100C", "101C", "102C", "103C", "104C", "105C", + "106C", "107C", "108C", "109C", "110C", "111C", "112C", "113C", + "114C", "115C", "116C", "117C", "118C", "119C", "120C", "121C", + "122C", "123C", "124C", "125C", "126C", "127C", "128C", "129C", + "130C", "131C", "132C", "133C", "134C", "135C", "136C", "137C", + "138C", "139C", "140C", "141C", "142C", "143C", "144C", "145C", + "146C", "147C", "148C", "149C", "150C" +}; + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh1_enum, + MAX98396_R2020_THERM_WARN_THRESH, 0, + max98396_thermal_thresh_text); + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_warn_thresh2_enum, + MAX98396_R2021_THERM_WARN_THRESH2, 0, + max98396_thermal_thresh_text); + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_shdn_thresh_enum, + MAX98396_R2022_THERM_SHDN_THRESH, 0, + max98396_thermal_thresh_text); + +static const char * const max98396_thermal_hyteresis_text[] = { + "2C", "5C", "7C", "10C" +}; + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_hysteresis_enum, + MAX98396_R2023_THERM_HYSTERESIS, 0, + max98396_thermal_hyteresis_text); + +static const char * const max98396_foldback_slope_text[] = { + "0.25", "0.5", "1.0", "2.0" +}; + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope1_enum, + MAX98396_R2024_THERM_FOLDBACK_SET, + MAX98396_THERM_FB_SLOPE1_SHIFT, + max98396_foldback_slope_text); + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_slope2_enum, + MAX98396_R2024_THERM_FOLDBACK_SET, + MAX98396_THERM_FB_SLOPE2_SHIFT, + max98396_foldback_slope_text); + +static const char * const max98396_foldback_reltime_text[] = { + "3ms", "10ms", "100ms", "300ms" +}; + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_reltime_enum, + MAX98396_R2024_THERM_FOLDBACK_SET, + MAX98396_THERM_FB_REL_SHIFT, + max98396_foldback_reltime_text); + +static const char * const max98396_foldback_holdtime_text[] = { + "0ms", "20ms", "40ms", "80ms" +}; + +static SOC_ENUM_SINGLE_DECL(max98396_thermal_fb_holdtime_enum, + MAX98396_R2024_THERM_FOLDBACK_SET, + MAX98396_THERM_FB_HOLD_SHIFT, + max98396_foldback_holdtime_text); + +static int max98396_adc_value_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); + int ret; + u8 val[2]; + int reg = mc->reg; + + /* ADC value is not available if the device is powered down */ + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) + goto exit; + + if (max98396->device_id == CODEC_TYPE_MAX98397) { + switch (mc->reg) { + case MAX98396_R20B6_ADC_PVDD_READBACK_MSB: + reg = MAX98397_R20B7_ADC_PVDD_READBACK_MSB; + break; + case MAX98396_R20B8_ADC_VBAT_READBACK_MSB: + reg = MAX98397_R20B9_ADC_VBAT_READBACK_MSB; + break; + case MAX98396_R20BA_ADC_TEMP_READBACK_MSB: + reg = MAX98397_R20BB_ADC_TEMP_READBACK_MSB; + break; + default: + goto exit; + } + } + + ret = regmap_raw_read(max98396->regmap, reg, &val, 2); + if (ret) + goto exit; + + /* ADC readback bits[8:0] rearrangement */ + ucontrol->value.integer.value[0] = (val[0] << 1) | (val[1] & 1); + return 0; + +exit: + ucontrol->value.integer.value[0] = 0; + return 0; +} + +static const struct snd_kcontrol_new max98396_snd_controls[] = { + /* Volume */ + SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL, + 0, 0x7F, 1, max98396_digital_tlv), + SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN, + 0, 0x11, 0, max98396_spk_tlv), + /* Volume Ramp Up/Down Enable*/ + SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0), + SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0), + /* Clock Monitor Enable */ + SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_CMON_EN_SHIFT, 1, 0), + /* Dither Enable */ + SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0), + SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0), + /* DC Blocker Enable */ + SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0), + SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0), + /* Speaker Safe Mode Enable */ + SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0), + /* Wideband Filter Enable */ + SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0), + SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0), + /* Dynamic Headroom Tracking */ + SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0), + /* Brownout Protection Engine */ + SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0), + SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0), + /* Bypass Path Enable */ + SOC_SINGLE("Bypass Path Switch", + MAX98396_R205E_PCM_RX_EN, 1, 1, 0), + /* Speaker Operation Mode */ + SOC_ENUM("OP Mode", max98396_op_mod_enum), + /* Auto Restart functions */ + SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL, + MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0), + SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0), + SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0), + SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0), + SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_OVC_RESTART_SHFT, 1, 0), + /* Thermal Threshold */ + SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum), + SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum), + SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum), + SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum), + SOC_SINGLE("THERM Foldback Switch", + MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0), + SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum), + SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum), + SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum), + SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum), + /* ADC */ + SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), + SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), + SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), +}; + +static const struct snd_kcontrol_new max98397_snd_controls[] = { + /* Volume */ + SOC_SINGLE_TLV("Digital Volume", MAX98396_R2090_AMP_VOL_CTRL, + 0, 0xFF, 1, max98397_digital_tlv), + SOC_SINGLE_TLV("Speaker Volume", MAX98396_R2091_AMP_PATH_GAIN, + 0, 0x15, 0, max98397_spk_tlv), + /* Volume Ramp Up/Down Enable*/ + SOC_SINGLE("Ramp Up Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0), + SOC_SINGLE("Ramp Down Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0), + /* Clock Monitor Enable */ + SOC_SINGLE("CLK Monitor Switch", MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_CMON_EN_SHIFT, 1, 0), + /* Dither Enable */ + SOC_SINGLE("Dither Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_DITH_EN_SHIFT, 1, 0), + SOC_SINGLE("IV Dither Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_DITH_EN_SHIFT, 1, 0), + /* DC Blocker Enable */ + SOC_SINGLE("DC Blocker Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_DCBLK_EN_SHIFT, 1, 0), + SOC_SINGLE("IV DC Blocker Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_DCBLK_EN_SHIFT, 3, 0), + /* Speaker Safe Mode Enable */ + SOC_SINGLE("Safe Mode Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_SAFE_EN_SHIFT, 1, 0), + /* Wideband Filter Enable */ + SOC_SINGLE("WB Filter Switch", MAX98396_R2092_AMP_DSP_CFG, + MAX98396_DSP_SPK_WB_FLT_EN_SHIFT, 1, 0), + SOC_SINGLE("IV WB Filter Switch", MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_WB_FLT_EN_SHIFT, 1, 0), + /* Dynamic Headroom Tracking */ + SOC_SINGLE("DHT Switch", MAX98396_R20DF_DHT_EN, 0, 1, 0), + /* Brownout Protection Engine */ + SOC_SINGLE("BPE Switch", MAX98396_R210D_BPE_EN, 0, 1, 0), + SOC_SINGLE("BPE Limiter Switch", MAX98396_R210D_BPE_EN, 1, 1, 0), + /* Bypass Path Enable */ + SOC_SINGLE("Bypass Path Switch", + MAX98396_R205E_PCM_RX_EN, 1, 1, 0), + /* Speaker Operation Mode */ + SOC_ENUM("OP Mode", max98396_op_mod_enum), + /* Auto Restart functions */ + SOC_SINGLE("CMON Auto Restart Switch", MAX98396_R2038_CLK_MON_CTRL, + MAX98396_CLK_MON_AUTO_RESTART_SHIFT, 1, 0), + SOC_SINGLE("PVDD Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_PVDD_UVLO_RESTART_SHFT, 1, 0), + SOC_SINGLE("VBAT Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_VBAT_UVLO_RESTART_SHFT, 1, 0), + SOC_SINGLE("THERM Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_THEM_SHDN_RESTART_SHFT, 1, 0), + SOC_SINGLE("OVC Auto Restart Switch", MAX98396_R210E_AUTO_RESTART, + MAX98396_OVC_RESTART_SHFT, 1, 0), + /* Thermal Threshold */ + SOC_ENUM("THERM Thresh1", max98396_thermal_warn_thresh1_enum), + SOC_ENUM("THERM Thresh2", max98396_thermal_warn_thresh2_enum), + SOC_ENUM("THERM SHDN Thresh", max98396_thermal_shdn_thresh_enum), + SOC_ENUM("THERM Hysteresis", max98396_thermal_hysteresis_enum), + SOC_SINGLE("THERM Foldback Switch", + MAX98396_R2027_THERM_FOLDBACK_EN, 0, 1, 0), + SOC_ENUM("THERM Slope1", max98396_thermal_fb_slope1_enum), + SOC_ENUM("THERM Slope2", max98396_thermal_fb_slope2_enum), + SOC_ENUM("THERM Release", max98396_thermal_fb_reltime_enum), + SOC_ENUM("THERM Hold", max98396_thermal_fb_holdtime_enum), + /* ADC */ + SOC_SINGLE_EXT("ADC PVDD", MAX98396_R20B6_ADC_PVDD_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), + SOC_SINGLE_EXT("ADC VBAT", MAX98396_R20B8_ADC_VBAT_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), + SOC_SINGLE_EXT("ADC TEMP", MAX98396_R20BA_ADC_TEMP_READBACK_MSB, 0, 0x1FF, 0, + max98396_adc_value_get, NULL), +}; + +static const struct snd_soc_dapm_route max98396_audio_map[] = { + /* Plabyack */ + {"DAI Sel Mux", "Left", "Amp Enable"}, + {"DAI Sel Mux", "Right", "Amp Enable"}, + {"DAI Sel Mux", "LeftRight", "Amp Enable"}, + {"BE_OUT", NULL, "DAI Sel Mux"}, + /* Capture */ + { "VI Sense", "Switch", "VMON" }, + { "VI Sense", "Switch", "IMON" }, + { "Voltage Sense", NULL, "VI Sense" }, + { "Current Sense", NULL, "VI Sense" }, +}; + +static struct snd_soc_dai_driver max98396_dai[] = { + { + .name = "max98396-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98396_RATES, + .formats = MAX98396_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98396_RATES, + .formats = MAX98396_FORMATS, + }, + .ops = &max98396_dai_ops, + } +}; + +static struct snd_soc_dai_driver max98397_dai[] = { + { + .name = "max98397-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98396_RATES, + .formats = MAX98396_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98396_RATES, + .formats = MAX98396_FORMATS, + }, + .ops = &max98396_dai_ops, + } +}; + +static void max98396_reset(struct max98396_priv *max98396, struct device *dev) +{ + int ret, reg, count; + + /* Software Reset */ + ret = regmap_write(max98396->regmap, + MAX98396_R2000_SW_RESET, 1); + if (ret) + dev_err(dev, "Reset command failed. (ret:%d)\n", ret); + + count = 0; + while (count < 3) { + usleep_range(5000, 6000); + /* Software Reset Verification */ + ret = regmap_read(max98396->regmap, + GET_REG_ADDR_REV_ID(max98396->device_id), ®); + if (!ret) { + dev_info(dev, "Reset completed (retry:%d)\n", count); + return; + } + count++; + } + dev_err(dev, "Reset failed. (ret:%d)\n", ret); +} + +static int max98396_probe(struct snd_soc_component *component) +{ + struct max98396_priv *max98396 = + snd_soc_component_get_drvdata(component); + + /* Software Reset */ + max98396_reset(max98396, component->dev); + + /* L/R mix configuration */ + if (max98396->device_id == CODEC_TYPE_MAX98396) { + regmap_write(max98396->regmap, + MAX98396_R2055_PCM_RX_SRC1, 0x02); + regmap_write(max98396->regmap, + MAX98396_R2056_PCM_RX_SRC2, 0x10); + } else { + regmap_write(max98396->regmap, + MAX98397_R2056_PCM_RX_SRC1, 0x02); + regmap_write(max98396->regmap, + MAX98397_R2057_PCM_RX_SRC2, 0x10); + } + /* Supply control */ + regmap_update_bits(max98396->regmap, + MAX98396_R20A0_AMP_SUPPLY_CTL, + MAX98396_AMP_SUPPLY_NOVBAT, + (max98396->vbat == NULL) ? + MAX98396_AMP_SUPPLY_NOVBAT : 0); + /* Enable DC blocker */ + regmap_update_bits(max98396->regmap, + MAX98396_R2092_AMP_DSP_CFG, 1, 1); + /* Enable IV Monitor DC blocker */ + regmap_update_bits(max98396->regmap, + MAX98396_R20E0_IV_SENSE_PATH_CFG, + MAX98396_IV_SENSE_DCBLK_EN_MASK, + MAX98396_IV_SENSE_DCBLK_EN_MASK); + /* Configure default data output sources */ + regmap_write(max98396->regmap, + MAX98396_R205D_PCM_TX_SRC_EN, 3); + /* Enable Wideband Filter */ + regmap_update_bits(max98396->regmap, + MAX98396_R2092_AMP_DSP_CFG, 0x40, 0x40); + /* Enable IV Wideband Filter */ + regmap_update_bits(max98396->regmap, + MAX98396_R20E0_IV_SENSE_PATH_CFG, 8, 8); + + /* Enable Bypass Source */ + regmap_write(max98396->regmap, + MAX98396_R2058_PCM_BYPASS_SRC, + max98396->bypass_slot); + /* Voltage, current slot configuration */ + regmap_write(max98396->regmap, + MAX98396_R2044_PCM_TX_CTRL_1, + max98396->v_slot); + regmap_write(max98396->regmap, + MAX98396_R2045_PCM_TX_CTRL_2, + max98396->i_slot); + regmap_write(max98396->regmap, + MAX98396_R204A_PCM_TX_CTRL_7, + max98396->spkfb_slot); + + if (max98396->v_slot < 8) + if (max98396->device_id == CODEC_TYPE_MAX98396) + regmap_update_bits(max98396->regmap, + MAX98396_R2053_PCM_TX_HIZ_CTRL_8, + 1 << max98396->v_slot, 0); + else + regmap_update_bits(max98396->regmap, + MAX98397_R2054_PCM_TX_HIZ_CTRL_8, + 1 << max98396->v_slot, 0); + else + if (max98396->device_id == CODEC_TYPE_MAX98396) + regmap_update_bits(max98396->regmap, + MAX98396_R2052_PCM_TX_HIZ_CTRL_7, + 1 << (max98396->v_slot - 8), 0); + else + regmap_update_bits(max98396->regmap, + MAX98397_R2053_PCM_TX_HIZ_CTRL_7, + 1 << (max98396->v_slot - 8), 0); + + if (max98396->i_slot < 8) + if (max98396->device_id == CODEC_TYPE_MAX98396) + regmap_update_bits(max98396->regmap, + MAX98396_R2053_PCM_TX_HIZ_CTRL_8, + 1 << max98396->i_slot, 0); + else + regmap_update_bits(max98396->regmap, + MAX98397_R2054_PCM_TX_HIZ_CTRL_8, + 1 << max98396->i_slot, 0); + else + if (max98396->device_id == CODEC_TYPE_MAX98396) + regmap_update_bits(max98396->regmap, + MAX98396_R2052_PCM_TX_HIZ_CTRL_7, + 1 << (max98396->i_slot - 8), 0); + else + regmap_update_bits(max98396->regmap, + MAX98397_R2053_PCM_TX_HIZ_CTRL_7, + 1 << (max98396->i_slot - 8), 0); + + /* Set interleave mode */ + if (max98396->interleave_mode) + regmap_update_bits(max98396->regmap, + MAX98396_R2041_PCM_MODE_CFG, + MAX98396_PCM_TX_CH_INTERLEAVE_MASK, + MAX98396_PCM_TX_CH_INTERLEAVE_MASK); + + regmap_update_bits(max98396->regmap, + MAX98396_R2038_CLK_MON_CTRL, + MAX98396_CLK_MON_AUTO_RESTART_MASK, + MAX98396_CLK_MON_AUTO_RESTART_MASK); + + regmap_update_bits(max98396->regmap, + MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_DMON_STUCK_EN_MASK, + max98396->dmon_stuck_enable ? + MAX98396_CTRL_DMON_STUCK_EN_MASK : 0); + + regmap_update_bits(max98396->regmap, + MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_DMON_MAG_EN_MASK, + max98396->dmon_mag_enable ? + MAX98396_CTRL_DMON_MAG_EN_MASK : 0); + + switch (max98396->dmon_duration) { + case 64: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 0); + break; + case 256: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 1); + break; + case 1024: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 2); + break; + case 4096: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 3); + break; + default: + dev_err(component->dev, "Invalid DMON duration %d\n", + max98396->dmon_duration); + } + + switch (max98396->dmon_stuck_threshold) { + case 15: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 0 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 13: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 1 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 22: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 2 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 9: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 3 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + default: + dev_err(component->dev, "Invalid DMON stuck threshold %d\n", + max98396->dmon_stuck_threshold); + } + + switch (max98396->dmon_mag_threshold) { + case 2 ... 5: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + (5 - max98396->dmon_mag_threshold) + << MAX98396_DMON_MAG_THRESH_SHIFT); + break; + default: + dev_err(component->dev, "Invalid DMON magnitude threshold %d\n", + max98396->dmon_mag_threshold); + } + + /* Speaker Amplifier PCM RX Enable by default */ + regmap_update_bits(max98396->regmap, + MAX98396_R205E_PCM_RX_EN, + MAX98396_PCM_RX_EN_MASK, 1); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int max98396_suspend(struct device *dev) +{ + struct max98396_priv *max98396 = dev_get_drvdata(dev); + + regcache_cache_only(max98396->regmap, true); + regcache_mark_dirty(max98396->regmap); + regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + if (max98396->pvdd) + regulator_disable(max98396->pvdd); + + if (max98396->vbat) + regulator_disable(max98396->vbat); + + return 0; +} + +static int max98396_resume(struct device *dev) +{ + struct max98396_priv *max98396 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + if (ret < 0) + return ret; + + if (max98396->pvdd) { + ret = regulator_enable(max98396->pvdd); + if (ret < 0) + return ret; + } + + if (max98396->vbat) { + ret = regulator_enable(max98396->vbat); + if (ret < 0) + return ret; + } + + regcache_cache_only(max98396->regmap, false); + max98396_reset(max98396, dev); + regcache_sync(max98396->regmap); + return 0; +} +#endif + +static const struct dev_pm_ops max98396_pm = { + SET_SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume) +}; + +static const struct snd_soc_component_driver soc_codec_dev_max98396 = { + .probe = max98396_probe, + .controls = max98396_snd_controls, + .num_controls = ARRAY_SIZE(max98396_snd_controls), + .dapm_widgets = max98396_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98396_dapm_widgets), + .dapm_routes = max98396_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98396_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct snd_soc_component_driver soc_codec_dev_max98397 = { + .probe = max98396_probe, + .controls = max98397_snd_controls, + .num_controls = ARRAY_SIZE(max98397_snd_controls), + .dapm_widgets = max98396_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98396_dapm_widgets), + .dapm_routes = max98396_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98396_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config max98396_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98396_R21FF_REVISION_ID, + .reg_defaults = max98396_reg, + .num_reg_defaults = ARRAY_SIZE(max98396_reg), + .readable_reg = max98396_readable_register, + .volatile_reg = max98396_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_config max98397_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98397_R22FF_REVISION_ID, + .reg_defaults = max98397_reg, + .num_reg_defaults = ARRAY_SIZE(max98397_reg), + .readable_reg = max98397_readable_register, + .volatile_reg = max98397_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static void max98396_read_device_property(struct device *dev, + struct max98396_priv *max98396) +{ + int value; + + if (!device_property_read_u32(dev, "adi,vmon-slot-no", &value)) + max98396->v_slot = value & 0xF; + else + max98396->v_slot = 0; + + if (!device_property_read_u32(dev, "adi,imon-slot-no", &value)) + max98396->i_slot = value & 0xF; + else + max98396->i_slot = 1; + + if (!device_property_read_u32(dev, "adi,spkfb-slot-no", &value)) + max98396->spkfb_slot = value & 0xF; + else + max98396->spkfb_slot = 2; + + if (!device_property_read_u32(dev, "adi,bypass-slot-no", &value)) + max98396->bypass_slot = value & 0xF; + else + max98396->bypass_slot = 0; + + max98396->dmon_stuck_enable = + device_property_read_bool(dev, "adi,dmon-stuck-enable"); + + if (!device_property_read_u32(dev, "adi,dmon-stuck-threshold-bits", &value)) + max98396->dmon_stuck_threshold = value; + else + max98396->dmon_stuck_threshold = 15; + + max98396->dmon_mag_enable = + device_property_read_bool(dev, "adi,dmon-magnitude-enable"); + + if (!device_property_read_u32(dev, "adi,dmon-magnitude-threshold-bits", &value)) + max98396->dmon_mag_threshold = value; + else + max98396->dmon_mag_threshold = 5; + + if (!device_property_read_u32(dev, "adi,dmon-duration-ms", &value)) + max98396->dmon_duration = value; + else + max98396->dmon_duration = 64; +} + +static void max98396_core_supplies_disable(void *priv) +{ + struct max98396_priv *max98396 = priv; + + regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); +} + +static void max98396_supply_disable(void *r) +{ + regulator_disable((struct regulator *) r); +} + +static int max98396_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max98396_priv *max98396 = NULL; + int i, ret, reg; + + max98396 = devm_kzalloc(&i2c->dev, sizeof(*max98396), GFP_KERNEL); + + if (!max98396) { + ret = -ENOMEM; + return ret; + } + i2c_set_clientdata(i2c, max98396); + + max98396->device_id = id->driver_data; + + /* regmap initialization */ + if (max98396->device_id == CODEC_TYPE_MAX98396) + max98396->regmap = devm_regmap_init_i2c(i2c, &max98396_regmap); + + else + max98396->regmap = devm_regmap_init_i2c(i2c, &max98397_regmap); + + if (IS_ERR(max98396->regmap)) { + ret = PTR_ERR(max98396->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + return ret; + } + + /* Obtain regulator supplies */ + for (i = 0; i < MAX98396_NUM_CORE_SUPPLIES; i++) + max98396->core_supplies[i].supply = max98396_core_supplies[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret); + return ret; + } + + max98396->vbat = devm_regulator_get_optional(&i2c->dev, "vbat"); + if (IS_ERR(max98396->vbat)) { + if (PTR_ERR(max98396->vbat) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + max98396->vbat = NULL; + } + + max98396->pvdd = devm_regulator_get_optional(&i2c->dev, "pvdd"); + if (IS_ERR(max98396->pvdd)) { + if (PTR_ERR(max98396->pvdd) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + max98396->pvdd = NULL; + } + + ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Unable to enable core supplies: %d", ret); + return ret; + } + + ret = devm_add_action_or_reset(&i2c->dev, max98396_core_supplies_disable, + max98396); + if (ret < 0) + return ret; + + if (max98396->pvdd) { + ret = regulator_enable(max98396->pvdd); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&i2c->dev, + max98396_supply_disable, + max98396->pvdd); + if (ret < 0) + return ret; + } + + if (max98396->vbat) { + ret = regulator_enable(max98396->vbat); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&i2c->dev, + max98396_supply_disable, + max98396->vbat); + if (ret < 0) + return ret; + } + + /* update interleave mode info */ + if (device_property_read_bool(&i2c->dev, "adi,interleave_mode")) + max98396->interleave_mode = true; + else + max98396->interleave_mode = false; + + /* voltage/current slot & gpio configuration */ + max98396_read_device_property(&i2c->dev, max98396); + + /* Reset the Device */ + max98396->reset_gpio = devm_gpiod_get_optional(&i2c->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(max98396->reset_gpio)) { + ret = PTR_ERR(max98396->reset_gpio); + dev_err(&i2c->dev, "Unable to request GPIO pin: %d.\n", ret); + return ret; + } + + if (max98396->reset_gpio) { + usleep_range(5000, 6000); + gpiod_set_value_cansleep(max98396->reset_gpio, 0); + /* Wait for the hw reset done */ + usleep_range(5000, 6000); + } + + ret = regmap_read(max98396->regmap, + GET_REG_ADDR_REV_ID(max98396->device_id), ®); + if (ret < 0) { + dev_err(&i2c->dev, "%s: failed to read revision of the device.\n", id->name); + return ret; + } + dev_info(&i2c->dev, "%s revision ID: 0x%02X\n", id->name, reg); + + /* codec registration */ + if (max98396->device_id == CODEC_TYPE_MAX98396) + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_max98396, + max98396_dai, + ARRAY_SIZE(max98396_dai)); + else + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_max98397, + max98397_dai, + ARRAY_SIZE(max98397_dai)); + if (ret < 0) + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + + return ret; +} + +static const struct i2c_device_id max98396_i2c_id[] = { + { "max98396", CODEC_TYPE_MAX98396}, + { "max98397", CODEC_TYPE_MAX98397}, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, max98396_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id max98396_of_match[] = { + { .compatible = "adi,max98396", }, + { .compatible = "adi,max98397", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98396_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id max98396_acpi_match[] = { + { "ADS8396", 0 }, + { "ADS8397", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, max98396_acpi_match); +#endif + +static struct i2c_driver max98396_i2c_driver = { + .driver = { + .name = "max98396", + .of_match_table = of_match_ptr(max98396_of_match), + .acpi_match_table = ACPI_PTR(max98396_acpi_match), + .pm = &max98396_pm, + }, + .probe = max98396_i2c_probe, + .id_table = max98396_i2c_id, +}; + +module_i2c_driver(max98396_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98396 driver"); +MODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98396.h b/sound/soc/codecs/max98396.h new file mode 100644 index 000000000000..d396aa3e698b --- /dev/null +++ b/sound/soc/codecs/max98396.h @@ -0,0 +1,327 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * max98396.h -- MAX98396 ALSA SoC audio driver header + * + * Copyright(c) 2022, Analog Devices Inc. + */ + +#ifndef _MAX98396_H +#define _MAX98396_H + +#define MAX98396_R2000_SW_RESET 0x2000 +#define MAX98396_R2001_INT_RAW1 0x2001 +#define MAX98396_R2002_INT_RAW2 0x2002 +#define MAX98396_R2003_INT_RAW3 0x2003 +#define MAX98396_R2004_INT_RAW4 0x2004 +#define MAX98396_R2006_INT_STATE1 0x2006 +#define MAX98396_R2007_INT_STATE2 0x2007 +#define MAX98396_R2008_INT_STATE3 0x2008 +#define MAX98396_R2009_INT_STATE4 0x2009 +#define MAX98396_R200B_INT_FLAG1 0x200B +#define MAX98396_R200C_INT_FLAG2 0x200C +#define MAX98396_R200D_INT_FLAG3 0x200D +#define MAX98396_R200E_INT_FLAG4 0x200E +#define MAX98396_R2010_INT_EN1 0x2010 +#define MAX98396_R2011_INT_EN2 0x2011 +#define MAX98396_R2012_INT_EN3 0x2012 +#define MAX98396_R2013_INT_EN4 0x2013 +#define MAX98396_R2015_INT_FLAG_CLR1 0x2015 +#define MAX98396_R2016_INT_FLAG_CLR2 0x2016 +#define MAX98396_R2017_INT_FLAG_CLR3 0x2017 +#define MAX98396_R2018_INT_FLAG_CLR4 0x2018 +#define MAX98396_R201F_IRQ_CTRL 0x201F +#define MAX98396_R2020_THERM_WARN_THRESH 0x2020 +#define MAX98396_R2021_THERM_WARN_THRESH2 0x2021 +#define MAX98396_R2022_THERM_SHDN_THRESH 0x2022 +#define MAX98396_R2023_THERM_HYSTERESIS 0x2023 +#define MAX98396_R2024_THERM_FOLDBACK_SET 0x2024 +#define MAX98396_R2027_THERM_FOLDBACK_EN 0x2027 +#define MAX98396_R2030_NOISEGATE_MODE_CTRL 0x2030 +#define MAX98396_R2033_NOISEGATE_MODE_EN 0x2033 +#define MAX98396_R2038_CLK_MON_CTRL 0x2038 +#define MAX98396_R2039_DATA_MON_CTRL 0x2039 +#define MAX98396_R203F_ENABLE_CTRLS 0x203F +#define MAX98396_R2040_PIN_CFG 0x2040 +#define MAX98396_R2041_PCM_MODE_CFG 0x2041 +#define MAX98396_R2042_PCM_CLK_SETUP 0x2042 +#define MAX98396_R2043_PCM_SR_SETUP 0x2043 +#define MAX98396_R2044_PCM_TX_CTRL_1 0x2044 +#define MAX98396_R2045_PCM_TX_CTRL_2 0x2045 +#define MAX98396_R2046_PCM_TX_CTRL_3 0x2046 +#define MAX98396_R2047_PCM_TX_CTRL_4 0x2047 +#define MAX98396_R2048_PCM_TX_CTRL_5 0x2048 +#define MAX98396_R2049_PCM_TX_CTRL_6 0x2049 +#define MAX98396_R204A_PCM_TX_CTRL_7 0x204A +#define MAX98396_R204B_PCM_TX_CTRL_8 0x204B +#define MAX98396_R204C_PCM_TX_HIZ_CTRL_1 0x204C +#define MAX98396_R204D_PCM_TX_HIZ_CTRL_2 0x204D +#define MAX98396_R204E_PCM_TX_HIZ_CTRL_3 0x204E +#define MAX98396_R204F_PCM_TX_HIZ_CTRL_4 0x204F +#define MAX98396_R2050_PCM_TX_HIZ_CTRL_5 0x2050 +#define MAX98396_R2051_PCM_TX_HIZ_CTRL_6 0x2051 +#define MAX98396_R2052_PCM_TX_HIZ_CTRL_7 0x2052 +#define MAX98396_R2053_PCM_TX_HIZ_CTRL_8 0x2053 +#define MAX98396_R2055_PCM_RX_SRC1 0x2055 +#define MAX98396_R2056_PCM_RX_SRC2 0x2056 +#define MAX98396_R2058_PCM_BYPASS_SRC 0x2058 +#define MAX98396_R205D_PCM_TX_SRC_EN 0x205D +#define MAX98396_R205E_PCM_RX_EN 0x205E +#define MAX98396_R205F_PCM_TX_EN 0x205F +#define MAX98396_R2070_ICC_RX_EN_A 0x2070 +#define MAX98396_R2071_ICC_RX_EN_B 0x2071 +#define MAX98396_R2072_ICC_TX_CTRL 0x2072 +#define MAX98396_R207F_ICC_EN 0x207F +#define MAX98396_R2083_TONE_GEN_DC_CFG 0x2083 +#define MAX98396_R2084_TONE_GEN_DC_LVL1 0x2084 +#define MAX98396_R2085_TONE_GEN_DC_LVL2 0x2085 +#define MAX98396_R2086_TONE_GEN_DC_LVL3 0x2086 +#define MAX98396_R208F_TONE_GEN_EN 0x208F +#define MAX98396_R2090_AMP_VOL_CTRL 0x2090 +#define MAX98396_R2091_AMP_PATH_GAIN 0x2091 +#define MAX98396_R2092_AMP_DSP_CFG 0x2092 +#define MAX98396_R2093_SSM_CFG 0x2093 +#define MAX98396_R2094_SPK_CLS_DG_THRESH 0x2094 +#define MAX98396_R2095_SPK_CLS_DG_HDR 0x2095 +#define MAX98396_R2096_SPK_CLS_DG_HOLD_TIME 0x2096 +#define MAX98396_R2097_SPK_CLS_DG_DELAY 0x2097 +#define MAX98396_R2098_SPK_CLS_DG_MODE 0x2098 +#define MAX98396_R2099_SPK_CLS_DG_VBAT_LVL 0x2099 +#define MAX98396_R209A_SPK_EDGE_CTRL 0x209A +#define MAX98396_R209C_SPK_EDGE_CTRL1 0x209C +#define MAX98396_R209D_SPK_EDGE_CTRL2 0x209D +#define MAX98396_R209E_AMP_CLIP_GAIN 0x209E +#define MAX98396_R209F_BYPASS_PATH_CFG 0x209F +#define MAX98396_R20A0_AMP_SUPPLY_CTL 0x20A0 +#define MAX98396_R20AF_AMP_EN 0x20AF +#define MAX98396_R20B0_ADC_SR 0x20B0 +#define MAX98396_R20B1_ADC_PVDD_CFG 0x20B1 +#define MAX98396_R20B2_ADC_VBAT_CFG 0x20B2 +#define MAX98396_R20B3_ADC_THERMAL_CFG 0x20B3 +#define MAX98396_R20B4_ADC_READBACK_CTRL1 0x20B4 +#define MAX98396_R20B5_ADC_READBACK_CTRL2 0x20B5 +#define MAX98396_R20B6_ADC_PVDD_READBACK_MSB 0x20B6 +#define MAX98396_R20B7_ADC_PVDD_READBACK_LSB 0x20B7 +#define MAX98396_R20B8_ADC_VBAT_READBACK_MSB 0x20B8 +#define MAX98396_R20B9_ADC_VBAT_READBACK_LSB 0x20B9 +#define MAX98396_R20BA_ADC_TEMP_READBACK_MSB 0x20BA +#define MAX98396_R20BB_ADC_TEMP_READBACK_LSB 0x20BB +#define MAX98396_R20BC_ADC_LO_PVDD_READBACK_MSB 0x20BC +#define MAX98396_R20BD_ADC_LO_PVDD_READBACK_LSB 0x20BD +#define MAX98396_R20BE_ADC_LO_VBAT_READBACK_MSB 0x20BE +#define MAX98396_R20BF_ADC_LO_VBAT_READBACK_LSB 0x20BF +#define MAX98396_R20C7_ADC_CFG 0x20C7 +#define MAX98396_R20D0_DHT_CFG1 0x20D0 +#define MAX98396_R20D1_LIMITER_CFG1 0x20D1 +#define MAX98396_R20D2_LIMITER_CFG2 0x20D2 +#define MAX98396_R20D3_DHT_CFG2 0x20D3 +#define MAX98396_R20D4_DHT_CFG3 0x20D4 +#define MAX98396_R20D5_DHT_CFG4 0x20D5 +#define MAX98396_R20D6_DHT_HYSTERESIS_CFG 0x20D6 +#define MAX98396_R20DF_DHT_EN 0x20DF +#define MAX98396_R20E0_IV_SENSE_PATH_CFG 0x20E0 +#define MAX98396_R20E4_IV_SENSE_PATH_EN 0x20E4 +#define MAX98396_R20E5_BPE_STATE 0x20E5 +#define MAX98396_R20E6_BPE_L3_THRESH_MSB 0x20E6 +#define MAX98396_R20E7_BPE_L3_THRESH_LSB 0x20E7 +#define MAX98396_R20E8_BPE_L2_THRESH_MSB 0x20E8 +#define MAX98396_R20E9_BPE_L2_THRESH_LSB 0x20E9 +#define MAX98396_R20EA_BPE_L1_THRESH_MSB 0x20EA +#define MAX98396_R20EB_BPE_L1_THRESH_LSB 0x20EB +#define MAX98396_R20EC_BPE_L0_THRESH_MSB 0x20EC +#define MAX98396_R20ED_BPE_L0_THRESH_LSB 0x20ED +#define MAX98396_R20EE_BPE_L3_DWELL_HOLD_TIME 0x20EE +#define MAX98396_R20EF_BPE_L2_DWELL_HOLD_TIME 0x20EF +#define MAX98396_R20F0_BPE_L1_DWELL_HOLD_TIME 0x20F0 +#define MAX98396_R20F1_BPE_L0_HOLD_TIME 0x20F1 +#define MAX98396_R20F2_BPE_L3_ATTACK_REL_STEP 0x20F2 +#define MAX98396_R20F3_BPE_L2_ATTACK_REL_STEP 0x20F3 +#define MAX98396_R20F4_BPE_L1_ATTACK_REL_STEP 0x20F4 +#define MAX98396_R20F5_BPE_L0_ATTACK_REL_STEP 0x20F5 +#define MAX98396_R20F6_BPE_L3_MAX_GAIN_ATTN 0x20F6 +#define MAX98396_R20F7_BPE_L2_MAX_GAIN_ATTN 0x20F7 +#define MAX98396_R20F8_BPE_L1_MAX_GAIN_ATTN 0x20F8 +#define MAX98396_R20F9_BPE_L0_MAX_GAIN_ATTN 0x20F9 +#define MAX98396_R20FA_BPE_L3_ATT_REL_RATE 0x20FA +#define MAX98396_R20FB_BPE_L2_ATT_REL_RATE 0x20FB +#define MAX98396_R20FC_BPE_L1_ATT_REL_RATE 0x20FC +#define MAX98396_R20FD_BPE_L0_ATT_REL_RATE 0x20FD +#define MAX98396_R20FE_BPE_L3_LIMITER_CFG 0x20FE +#define MAX98396_R20FF_BPE_L2_LIMITER_CFG 0x20FF +#define MAX98396_R2100_BPE_L1_LIMITER_CFG 0x2100 +#define MAX98396_R2101_BPE_L0_LIMITER_CFG 0x2101 +#define MAX98396_R2102_BPE_L3_LIM_ATT_REL_RATE 0x2102 +#define MAX98396_R2103_BPE_L2_LIM_ATT_REL_RATE 0x2103 +#define MAX98396_R2104_BPE_L1_LIM_ATT_REL_RATE 0x2104 +#define MAX98396_R2105_BPE_L0_LIM_ATT_REL_RATE 0x2105 +#define MAX98396_R2106_BPE_THRESH_HYSTERESIS 0x2106 +#define MAX98396_R2107_BPE_INFINITE_HOLD_CLR 0x2107 +#define MAX98396_R2108_BPE_SUPPLY_SRC 0x2108 +#define MAX98396_R2109_BPE_LOW_STATE 0x2109 +#define MAX98396_R210A_BPE_LOW_GAIN 0x210A +#define MAX98396_R210B_BPE_LOW_LIMITER 0x210B +#define MAX98396_R210D_BPE_EN 0x210D +#define MAX98396_R210E_AUTO_RESTART 0x210E +#define MAX98396_R210F_GLOBAL_EN 0x210F +#define MAX98396_R21FF_REVISION_ID 0x21FF + +/* MAX98927 Registers */ +#define MAX98397_R203A_SPK_MON_THRESH 0x203A +#define MAX98397_R204C_PCM_TX_CTRL_9 0x204C +#define MAX98397_R204D_PCM_TX_HIZ_CTRL_1 0x204D +#define MAX98397_R204E_PCM_TX_HIZ_CTRL_2 0x204E +#define MAX98397_R204F_PCM_TX_HIZ_CTRL_3 0x204F +#define MAX98397_R2050_PCM_TX_HIZ_CTRL_4 0x2050 +#define MAX98397_R2051_PCM_TX_HIZ_CTRL_5 0x2051 +#define MAX98397_R2052_PCM_TX_HIZ_CTRL_6 0x2052 +#define MAX98397_R2053_PCM_TX_HIZ_CTRL_7 0x2053 +#define MAX98397_R2054_PCM_TX_HIZ_CTRL_8 0x2054 +#define MAX98397_R2056_PCM_RX_SRC1 0x2056 +#define MAX98397_R2057_PCM_RX_SRC2 0x2057 +#define MAX98397_R2060_PCM_TX_SUPPLY_SEL 0x2060 +#define MAX98397_R209B_SPK_PATH_WB_ONLY 0x209B +#define MAX98397_R20B4_ADC_VDDH_CFG 0x20B4 +#define MAX98397_R20B5_ADC_READBACK_CTRL1 0x20B5 +#define MAX98397_R20B6_ADC_READBACK_CTRL2 0x20B6 +#define MAX98397_R20B7_ADC_PVDD_READBACK_MSB 0x20B7 +#define MAX98397_R20B8_ADC_PVDD_READBACK_LSB 0x20B8 +#define MAX98397_R20B9_ADC_VBAT_READBACK_MSB 0x20B9 +#define MAX98397_R20BA_ADC_VBAT_READBACK_LSB 0x20BA +#define MAX98397_R20BB_ADC_TEMP_READBACK_MSB 0x20BB +#define MAX98397_R20BC_ADC_TEMP_READBACK_LSB 0x20BC +#define MAX98397_R20BD_ADC_VDDH__READBACK_MSB 0x20BD +#define MAX98397_R20BE_ADC_VDDH_READBACK_LSB 0x20BE +#define MAX98397_R20BF_ADC_LO_PVDD_READBACK_MSB 0x20BF +#define MAX98397_R20C0_ADC_LO_PVDD_READBACK_LSB 0x20C0 +#define MAX98397_R20C1_ADC_LO_VBAT_READBACK_MSB 0x20C1 +#define MAX98397_R20C2_ADC_LO_VBAT_READBACK_LSB 0x20C2 +#define MAX98397_R20C3_ADC_LO_VDDH_READBACK_MSB 0x20C3 +#define MAX98397_R20C4_ADC_LO_VDDH_READBACK_LSB 0x20C4 +#define MAX98397_R20C5_MEAS_ADC_OPTIMAL_MODE 0x20C5 +#define MAX98397_R22FF_REVISION_ID 0x22FF + +#define GET_REG_ADDR_REV_ID(x)\ + ((x) > 0 ? MAX98397_R22FF_REVISION_ID : MAX98396_R21FF_REVISION_ID) + +/* MAX98396_R2024_THERM_FOLDBACK_SET */ +#define MAX98396_THERM_FB_SLOPE1_SHIFT (0) +#define MAX98396_THERM_FB_SLOPE2_SHIFT (2) +#define MAX98396_THERM_FB_REL_SHIFT (4) +#define MAX98396_THERM_FB_HOLD_SHIFT (6) + +/* MAX98396_R2038_CLK_MON_CTRL */ +#define MAX98396_CLK_MON_AUTO_RESTART_MASK (0x1 << 0) +#define MAX98396_CLK_MON_AUTO_RESTART_SHIFT (0) + +/* MAX98396_R2039_DATA_MON_CTRL */ +#define MAX98396_DMON_MAG_THRESH_SHIFT (4) +#define MAX98396_DMON_MAG_THRESH_MASK (0x3 << MAX98396_DMON_MAG_THRESH_SHIFT) +#define MAX98396_DMON_STUCK_THRESH_SHIFT (2) +#define MAX98396_DMON_STUCK_THRESH_MASK (0x3 << MAX98396_DMON_STUCK_THRESH_SHIFT) +#define MAX98396_DMON_DURATION_MASK (0x3) + +/* MAX98396_R203F_ENABLE_CTRLS */ +#define MAX98396_CTRL_CMON_EN_SHIFT (0) +#define MAX98396_CTRL_DMON_STUCK_EN_MASK (0x1 << 1) +#define MAX98396_CTRL_DMON_MAG_EN_MASK (0x1 << 2) + +/* MAX98396_R2041_PCM_MODE_CFG */ +#define MAX98396_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3) +#define MAX98396_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2) +#define MAX98396_PCM_FORMAT_I2S (0x0 << 3) +#define MAX98396_PCM_FORMAT_LJ (0x1 << 3) +#define MAX98396_PCM_FORMAT_TDM_MODE0 (0x3 << 3) +#define MAX98396_PCM_FORMAT_TDM_MODE1 (0x4 << 3) +#define MAX98396_PCM_FORMAT_TDM_MODE2 (0x5 << 3) +#define MAX98396_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6) +#define MAX98396_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6) +#define MAX98396_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6) +#define MAX98396_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6) +#define MAX98396_PCM_MODE_CFG_LRCLKEDGE (0x1 << 1) + +/* MAX98396_R2042_PCM_CLK_SETUP */ +#define MAX98396_PCM_MODE_CFG_BCLKEDGE (0x1 << 4) +#define MAX98396_PCM_CLK_SETUP_BSEL_MASK (0xF << 0) +#define MAX98396_PCM_BCLKEDGE_BSEL_MASK (0x1F) + +/* MAX98396_R2043_PCM_SR_SETUP */ +#define MAX98396_PCM_SR_SHIFT (0) +#define MAX98396_IVADC_SR_SHIFT (4) +#define MAX98396_PCM_SR_MASK (0xF << MAX98396_PCM_SR_SHIFT) +#define MAX98396_IVADC_SR_MASK (0xF << MAX98396_IVADC_SR_SHIFT) +#define MAX98396_PCM_SR_8000 (0) +#define MAX98396_PCM_SR_11025 (1) +#define MAX98396_PCM_SR_12000 (2) +#define MAX98396_PCM_SR_16000 (3) +#define MAX98396_PCM_SR_22050 (4) +#define MAX98396_PCM_SR_24000 (5) +#define MAX98396_PCM_SR_32000 (6) +#define MAX98396_PCM_SR_44100 (7) +#define MAX98396_PCM_SR_48000 (8) +#define MAX98396_PCM_SR_88200 (9) +#define MAX98396_PCM_SR_96000 (10) +#define MAX98396_PCM_SR_176400 (11) +#define MAX98396_PCM_SR_192000 (12) + +/* MAX98396_R2055_PCM_RX_SRC1 */ +#define MAX98396_PCM_RX_MASK (0x3 << 0) + +/* MAX98396_R2056_PCM_RX_SRC2 */ +#define MAX98396_PCM_DMIX_CH1_SHIFT (0xF << 0) +#define MAX98396_PCM_DMIX_CH0_SRC_MASK (0xF << 0) +#define MAX98396_PCM_DMIX_CH1_SRC_MASK (0xF << MAX98396_PCM_DMIX_CH1_SHIFT) + +/* MAX98396_R205E_PCM_RX_EN */ +#define MAX98396_PCM_RX_EN_MASK (0x1 << 0) +#define MAX98396_PCM_RX_BYP_EN_MASK (0x1 << 1) + +/* MAX98396_R2092_AMP_DSP_CFG */ +#define MAX98396_DSP_SPK_DCBLK_EN_SHIFT (0) +#define MAX98396_DSP_SPK_DITH_EN_SHIFT (1) +#define MAX98396_DSP_SPK_INVERT_SHIFT (2) +#define MAX98396_DSP_SPK_VOL_RMPUP_SHIFT (3) +#define MAX98396_DSP_SPK_VOL_RMPDN_SHIFT (4) +#define MAX98396_DSP_SPK_SAFE_EN_SHIFT (5) +#define MAX98396_DSP_SPK_WB_FLT_EN_SHIFT (6) + +/* MAX98396_R20A0_AMP_SUPPLY_CTL */ +#define MAX98396_AMP_SUPPLY_NOVBAT (0x1 << 0) + +/* MAX98396_R20E0_IV_SENSE_PATH_CFG */ +#define MAX98396_IV_SENSE_DCBLK_EN_MASK (0x3 << 0) +#define MAX98396_IV_SENSE_DCBLK_EN_SHIFT (0) +#define MAX98396_IV_SENSE_DITH_EN_SHIFT (2) +#define MAX98396_IV_SENSE_WB_FLT_EN_SHIFT (3) + +/* MAX98396_R210E_AUTO_RESTART_BEHAVIOR */ +#define MAX98396_PVDD_UVLO_RESTART_SHFT (0) +#define MAX98396_VBAT_UVLO_RESTART_SHFT (1) +#define MAX98396_THEM_SHDN_RESTART_SHFT (2) +#define MAX98396_OVC_RESTART_SHFT (3) + +enum { + CODEC_TYPE_MAX98396, + CODEC_TYPE_MAX98397, +}; + +#define MAX98396_NUM_CORE_SUPPLIES 3 + +struct max98396_priv { + struct regmap *regmap; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data core_supplies[MAX98396_NUM_CORE_SUPPLIES]; + struct regulator *pvdd, *vbat; + unsigned int v_slot; + unsigned int i_slot; + unsigned int spkfb_slot; + unsigned int bypass_slot; + bool dmon_stuck_enable; + unsigned int dmon_stuck_threshold; + bool dmon_mag_enable; + unsigned int dmon_mag_threshold; + unsigned int dmon_duration; + bool interleave_mode; + bool tdm_mode; + int tdm_max_samplerate; + int device_id; +}; +#endif diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index dec51893af74..a6733396b0ca 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -173,12 +173,12 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct snd_soc_component *component = codec_dai->component; u8 da = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* set clock provider for audio interface */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: da |= MAX9850_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -296,11 +296,9 @@ static const struct snd_soc_component_driver soc_component_dev_max9850 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int max9850_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max9850_i2c_probe(struct i2c_client *i2c) { struct max9850_priv *max9850; int ret; @@ -331,7 +329,7 @@ static struct i2c_driver max9850_i2c_driver = { .driver = { .name = "max9850", }, - .probe = max9850_i2c_probe, + .probe_new = max9850_i2c_probe, .id_table = max9850_i2c_id, }; diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c index a5aa124c4a2e..0daa2a3dd621 100644 --- a/sound/soc/codecs/max98504.c +++ b/sound/soc/codecs/max98504.c @@ -291,6 +291,7 @@ static const struct snd_soc_component_driver max98504_component_driver = { .num_dapm_widgets = ARRAY_SIZE(max98504_dapm_widgets), .dapm_routes = max98504_dapm_routes, .num_dapm_routes = ARRAY_SIZE(max98504_dapm_routes), + .endianness = 1, }; static const struct regmap_config max98504_regmap = { @@ -304,8 +305,7 @@ static const struct regmap_config max98504_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98504_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max98504_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *node = dev->of_node; @@ -371,7 +371,7 @@ static struct i2c_driver max98504_i2c_driver = { .name = "max98504", .of_match_table = of_match_ptr(max98504_of_match), }, - .probe = max98504_i2c_probe, + .probe_new = max98504_i2c_probe, .id_table = max98504_i2c_id, }; module_i2c_driver(max98504_i2c_driver); diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c index bb8649cd421c..5edd6f90f8a7 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -657,7 +657,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98520 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98520_regmap = { @@ -677,7 +676,7 @@ static void max98520_power_on(struct max98520_priv *max98520, bool poweron) gpiod_set_value_cansleep(max98520->reset_gpio, !poweron); } -static int max98520_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int max98520_i2c_probe(struct i2c_client *i2c) { int ret; int reg = 0; @@ -757,7 +756,7 @@ static struct i2c_driver max98520_i2c_driver = { .of_match_table = of_match_ptr(max98520_of_match), .pm = &max98520_pm, }, - .probe = max98520_i2c_probe, + .probe_new = max98520_i2c_probe, .id_table = max98520_i2c_id, }; diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index dd29b183ecd6..9611ab1e79e5 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -268,11 +268,11 @@ static int max9860_hw_params(struct snd_pcm_substream *substream, if (params_channels(params) == 2) ifc1b |= MAX9860_ST; - switch (max9860->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (max9860->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = MAX9860_MASTER; break; default: @@ -448,9 +448,9 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: max9860->fmt = fmt; return 0; @@ -537,7 +537,6 @@ static const struct snd_soc_component_driver max9860_component_driver = { .num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #ifdef CONFIG_PM @@ -606,12 +605,9 @@ static int max9860_probe(struct i2c_client *i2c) return -ENOMEM; max9860->dvddio = devm_regulator_get(dev, "DVDDIO"); - if (IS_ERR(max9860->dvddio)) { - ret = PTR_ERR(max9860->dvddio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get DVDDIO supply: %d\n", ret); - return ret; - } + if (IS_ERR(max9860->dvddio)) + return dev_err_probe(dev, PTR_ERR(max9860->dvddio), + "Failed to get DVDDIO supply\n"); max9860->dvddio_nb.notifier_call = max9860_dvddio_event; @@ -643,8 +639,7 @@ static int max9860_probe(struct i2c_client *i2c) if (IS_ERR(mclk)) { ret = PTR_ERR(mclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get MCLK: %d\n", ret); + dev_err_probe(dev, ret, "Failed to get MCLK\n"); goto err_regulator; } @@ -706,14 +701,13 @@ err_regulator: return ret; } -static int max9860_remove(struct i2c_client *i2c) +static void max9860_remove(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct max9860_priv *max9860 = dev_get_drvdata(dev); pm_runtime_disable(dev); regulator_disable(max9860->dvddio); - return 0; } static const struct i2c_device_id max9860_i2c_id[] = { diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 09b2d730e9fd..6d2941a9dbd6 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -19,7 +19,7 @@ struct max9867_priv { struct regmap *regmap; const struct snd_pcm_hw_constraint_list *constraints; unsigned int sysclk, pclk; - bool master, dsp_a; + bool provider, dsp_a; unsigned int adc_dac_active; }; @@ -335,7 +335,7 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream, MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8); regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, MAX9867_NI_LOW_MASK, 0x00FF & ni); - if (max9867->master) { + if (max9867->provider) { if (max9867->dsp_a) { value = MAX9867_IFC1B_48X; } else { @@ -442,14 +442,14 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); u8 iface1A, iface1B; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - max9867->master = true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + max9867->provider = true; iface1A = MAX9867_MASTER; iface1B = MAX9867_IFC1B_48X; break; - case SND_SOC_DAIFMT_CBS_CFS: - max9867->master = false; + case SND_SOC_DAIFMT_CBC_CFC: + max9867->provider = false; iface1A = iface1B = 0; break; default: @@ -589,7 +589,6 @@ static const struct snd_soc_component_driver max9867_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool max9867_volatile_register(struct device *dev, unsigned int reg) @@ -613,8 +612,7 @@ static const struct regmap_config max9867_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max9867_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max9867_i2c_probe(struct i2c_client *i2c) { struct max9867_priv *max9867; int ret, reg; @@ -662,7 +660,7 @@ static struct i2c_driver max9867_i2c_driver = { .name = "max9867", .of_match_table = of_match_ptr(max9867_of_match), }, - .probe = max9867_i2c_probe, + .probe_new = max9867_i2c_probe, .id_table = max9867_i2c_id, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 71fede9224c4..3bf86328d5cd 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -133,8 +133,7 @@ static const struct regmap_config max9877_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max9877_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max9877_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int i; @@ -161,7 +160,7 @@ static struct i2c_driver max9877_i2c_driver = { .driver = { .name = "max9877", }, - .probe = max9877_i2c_probe, + .probe_new = max9877_i2c_probe, .id_table = max9877_i2c_id, }; diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index ddaccc24b0cb..c24d9f2c8874 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -300,25 +300,22 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int invert = 0; dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* set DAI to slave mode */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE2, M98925_DAI_MAS_MASK, 0); max98925_set_sense_data(max98925); break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: /* - * set left channel DAI to master mode, - * right channel always slave + * set left channel DAI to provider mode, + * right channel always consumer */ regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE2, M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK); break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: dev_err(component->dev, "DAI clock mode unsupported"); return -EINVAL; @@ -547,7 +544,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98925 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98925_regmap = { @@ -561,8 +557,7 @@ static const struct regmap_config max98925_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98925_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98925_i2c_probe(struct i2c_client *i2c) { int ret, reg; u32 value; @@ -640,7 +635,7 @@ static struct i2c_driver max98925_i2c_driver = { .name = "max98925", .of_match_table = of_match_ptr(max98925_of_match), }, - .probe = max98925_i2c_probe, + .probe_new = max98925_i2c_probe, .id_table = max98925_i2c_id, }; diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index f286e572263e..bffd56e240e9 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -331,8 +331,8 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: max98926_set_sense_data(max98926); break; default: @@ -496,7 +496,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98926 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98926_regmap = { @@ -510,8 +509,7 @@ static const struct regmap_config max98926_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int max98926_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98926_i2c_probe(struct i2c_client *i2c) { int ret, reg; u32 value; @@ -584,7 +582,7 @@ static struct i2c_driver max98926_i2c_driver = { .name = "max98926", .of_match_table = of_match_ptr(max98926_of_match), }, - .probe = max98926_i2c_probe, + .probe_new = max98926_i2c_probe, .id_table = max98926_i2c_id, }; diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 5ba5f876eab8..331d3e1d735c 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -16,6 +16,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of_gpio.h> #include <sound/tlv.h> #include "max98927.h" @@ -147,12 +148,13 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + max98927->provider = false; mode = MAX98927_PCM_MASTER_MODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: - max98927->master = true; + case SND_SOC_DAIFMT_CBP_CFP: + max98927->provider = true; mode = MAX98927_PCM_MASTER_MODE_MASTER; break; default: @@ -269,7 +271,7 @@ static int max98927_set_clock(struct max98927_priv *max98927, int blr_clk_ratio = params_channels(params) * max98927->ch_size; int value; - if (max98927->master) { + if (max98927->provider) { int i; /* match rate to closest value */ for (i = 0; i < ARRAY_SIZE(rate_table); i++) { @@ -830,7 +832,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98927 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config max98927_regmap = { @@ -861,8 +862,7 @@ static void max98927_slot_config(struct i2c_client *i2c, max98927->i_l_slot = 1; } -static int max98927_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int max98927_i2c_probe(struct i2c_client *i2c) { int ret = 0, value; @@ -934,15 +934,13 @@ static int max98927_i2c_probe(struct i2c_client *i2c, return ret; } -static int max98927_i2c_remove(struct i2c_client *i2c) +static void max98927_i2c_remove(struct i2c_client *i2c) { struct max98927_priv *max98927 = i2c_get_clientdata(i2c); if (max98927->reset_gpio) { gpiod_set_value_cansleep(max98927->reset_gpio, 1); } - - return 0; } static const struct i2c_device_id max98927_i2c_id[] = { @@ -975,7 +973,7 @@ static struct i2c_driver max98927_i2c_driver = { .acpi_match_table = ACPI_PTR(max98927_acpi_match), .pm = &max98927_pm, }, - .probe = max98927_i2c_probe, + .probe_new = max98927_i2c_probe, .remove = max98927_i2c_remove, .id_table = max98927_i2c_id, }; diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h index 13f5066d7419..2353910f5f17 100644 --- a/sound/soc/codecs/max98927.h +++ b/sound/soc/codecs/max98927.h @@ -264,7 +264,7 @@ struct max98927_priv { unsigned int ch_size; unsigned int rate; unsigned int iface; - unsigned int master; + unsigned int provider; unsigned int digital_gain; bool tdm_mode; }; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index a21072503cb9..71490f11d96a 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -181,15 +181,14 @@ static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt, } /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: val |= AUDIO_C_CLK_EN; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: val |= AUDIO_CSM; break; - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFM: + default: return -EINVAL; } @@ -217,11 +216,11 @@ static int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt) return ret; /* - * In synchronous mode force the voice codec into slave mode + * In synchronous mode force the voice codec into consumer mode * so that the clock / framesync from the stereo DAC is used */ - fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; - fmt |= SND_SOC_DAIFMT_CBS_CFS; + fmt &= ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + fmt |= SND_SOC_DAIFMT_CBC_CFC; ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC); return ret; @@ -728,7 +727,6 @@ static const struct snd_soc_component_driver soc_component_dev_mc13783 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int __init mc13783_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 4d7c0be2a4aa..3c6ac77379cb 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -402,12 +402,11 @@ static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned char mode; struct snd_soc_component *component = codec_dai->component; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: mode = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: mode = 0; break; default: @@ -538,7 +537,6 @@ static const struct snd_soc_component_driver soc_component_dev_ml26124 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ml26124_i2c_regmap = { @@ -551,8 +549,7 @@ static const struct regmap_config ml26124_i2c_regmap = { .write_flag_mask = 0x01, }; -static int ml26124_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ml26124_i2c_probe(struct i2c_client *i2c) { struct ml26124_priv *priv; int ret; @@ -584,7 +581,7 @@ static struct i2c_driver ml26124_i2c_driver = { .driver = { .name = "ml26124", }, - .probe = ml26124_i2c_probe, + .probe_new = ml26124_i2c_probe, .id_table = ml26124_i2c_id, }; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 3ddd822240e3..78e543eb3c83 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -822,8 +822,8 @@ static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { {"EAR PA", NULL, "EAR CP"}, /* Headset (RX MIX1 and RX MIX2) */ - {"HEADPHONE", NULL, "HPHL PA"}, - {"HEADPHONE", NULL, "HPHR PA"}, + {"HPH_L", NULL, "HPHL PA"}, + {"HPH_R", NULL, "HPHR PA"}, {"HPHL DAC", NULL, "EAR_HPHL_CLK"}, {"HPHR DAC", NULL, "EAR_HPHR_CLK"}, @@ -870,7 +870,8 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AMIC3"), SND_SOC_DAPM_INPUT("AMIC2"), SND_SOC_DAPM_OUTPUT("EAR"), - SND_SOC_DAPM_OUTPUT("HEADPHONE"), + SND_SOC_DAPM_OUTPUT("HPH_L"), + SND_SOC_DAPM_OUTPUT("HPH_R"), /* RX stuff */ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), @@ -1127,7 +1128,6 @@ static const struct snd_soc_component_driver pm8916_wcd_analog = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pm8916_wcd_analog_parse_dt(struct device *dev, @@ -1221,8 +1221,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto err_disable_clk; + } ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1234,8 +1236,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto err_disable_clk; + } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1246,8 +1250,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto err_disable_clk; + } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, @@ -1264,6 +1270,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); + +err_disable_clk: + clk_disable_unprepare(priv->mclk); + return ret; } static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index fcc10c8bc625..d490a0f18675 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -328,8 +328,8 @@ static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM( static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM( "RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum); -/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ -static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); +/* Digital Gain control -84 dB to +40 dB in 1 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); /* Cutoff Freq for High Pass Filter at -3dB */ static const char * const hpf_cutoff_text[] = { @@ -510,15 +510,15 @@ static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, - -128, 127, digital_gain), + -84, 40, digital_gain), SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), @@ -553,22 +553,22 @@ static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3), WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4), WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL, + -84, 40, digital_gain), }; @@ -1155,7 +1155,6 @@ static const struct snd_soc_component_driver msm8916_wcd_digital = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config msm8916_codec_regmap_config = { @@ -1201,14 +1200,24 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->mclk); if (ret < 0) { dev_err(dev, "failed to enable mclk %d\n", ret); - return ret; + goto err_clk; } dev_set_drvdata(dev, priv); - return devm_snd_soc_register_component(dev, &msm8916_wcd_digital, + ret = devm_snd_soc_register_component(dev, &msm8916_wcd_digital, msm8916_wcd_digital_dai, ARRAY_SIZE(msm8916_wcd_digital_dai)); + if (ret) + goto err_mclk; + + return 0; + +err_mclk: + clk_disable_unprepare(priv->mclk); +err_clk: + clk_disable_unprepare(priv->ahbclk); + return ret; } static int msm8916_wcd_digital_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index 5c0536eb1044..d2cf4847eead 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -282,12 +282,9 @@ static const struct snd_soc_dai_ops mt6351_codec_dai_ops = { .hw_params = mt6351_codec_dai_hw_params, }; -#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6351_dai_driver[] = { { @@ -1448,6 +1445,7 @@ static const struct snd_soc_component_driver mt6351_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6351_dapm_widgets), .dapm_routes = mt6351_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6351_dapm_routes), + .endianness = 1, }; static int mt6351_codec_driver_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 9b263a9a669d..93f35e8d26fc 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -107,6 +107,7 @@ int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, priv->mtkaif_protocol = mtkaif_protocol; return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol); static void playback_gpio_set(struct mt6358_priv *priv) { @@ -273,6 +274,7 @@ int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) { @@ -296,6 +298,7 @@ int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) capture_gpio_reset(priv); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, int phase_1, int phase_2) @@ -310,6 +313,7 @@ int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); /* dl pga gain */ enum { @@ -2336,12 +2340,9 @@ static const struct snd_soc_dai_ops mt6358_codec_dai_ops = { .hw_params = mt6358_codec_dai_hw_params, }; -#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6358_dai_driver[] = { { @@ -2429,6 +2430,7 @@ static const struct snd_soc_component_driver mt6358_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6358_dapm_widgets), .dapm_routes = mt6358_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6358_dapm_routes), + .endianness = 1, }; static void mt6358_parse_dt(struct mt6358_priv *priv) @@ -2477,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev) static const struct of_device_id mt6358_of_match[] = { {.compatible = "mediatek,mt6358-sound",}, + {.compatible = "mediatek,mt6366-sound",}, {} }; MODULE_DEVICE_TABLE(of, mt6358_of_match); diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index 6d3d170144a0..7f624854948c 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -675,6 +675,7 @@ static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv) sizeof(struct three_key_threshold)); } + of_node_put(node); dev_warn(priv->dev, "accdet caps=%x\n", priv->caps); return 0; @@ -964,7 +965,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) mutex_init(&priv->res_lock); priv->accdet_irq = platform_get_irq(pdev, 0); - if (priv->accdet_irq) { + if (priv->accdet_irq >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq, NULL, mt6359_accdet_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, @@ -978,7 +979,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) if (priv->caps & ACCDET_PMIC_EINT0) { priv->accdet_eint0 = platform_get_irq(pdev, 1); - if (priv->accdet_eint0) { + if (priv->accdet_eint0 >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_eint0, NULL, mt6359_accdet_irq, @@ -993,7 +994,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) } } else if (priv->caps & ACCDET_PMIC_EINT1) { priv->accdet_eint1 = platform_get_irq(pdev, 2); - if (priv->accdet_eint1) { + if (priv->accdet_eint1 >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_eint1, NULL, mt6359_accdet_irq, diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index f8532aa7e4aa..c9a453ce8a2a 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -2576,12 +2576,9 @@ static const struct snd_soc_dai_ops mt6359_codec_dai_ops = { .shutdown = mt6359_codec_dai_shutdown, }; -#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static struct snd_soc_dai_driver mt6359_dai_driver[] = { { @@ -2739,6 +2736,7 @@ static const struct snd_soc_component_driver mt6359_soc_component_driver = { .num_dapm_widgets = ARRAY_SIZE(mt6359_dapm_widgets), .dapm_routes = mt6359_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6359_dapm_routes), + .endianness = 1, }; static int mt6359_parse_dt(struct mt6359_priv *priv) @@ -2780,6 +2778,7 @@ static int mt6359_parse_dt(struct mt6359_priv *priv) ret = of_property_read_u32(np, "mediatek,mic-type-2", &priv->mux_select[MUX_MIC_TYPE_2]); + of_node_put(np); if (ret) { dev_info(priv->dev, "%s() failed to read mic-type-2, use default (%d)\n", diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index 358c500377df..cc2df5f7ea19 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -47,13 +47,12 @@ static int mt6660_reg_write(void *context, unsigned int reg, unsigned int val) struct mt6660_chip *chip = context; int size = mt6660_get_reg_size(reg); u8 reg_data[4]; - int i, ret; + int i; for (i = 0; i < size; i++) reg_data[size - i - 1] = (val >> (8 * i)) & 0xff; - ret = i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); - return ret; + return i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); } static int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val) @@ -324,6 +323,7 @@ static const struct snd_soc_component_driver mt6660_component_driver = { .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes), .idle_bias_on = false, /* idle_bias_off = true */ + .endianness = 1, }; static int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream, @@ -457,8 +457,7 @@ static int _mt6660_read_chip_revision(struct mt6660_chip *chip) return 0; } -static int mt6660_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mt6660_i2c_probe(struct i2c_client *client) { struct mt6660_chip *chip = NULL; int ret; @@ -510,21 +509,24 @@ static int mt6660_i2c_probe(struct i2c_client *client, ret = devm_snd_soc_register_component(chip->dev, &mt6660_component_driver, &mt6660_codec_dai, 1); + if (ret) + pm_runtime_disable(chip->dev); + return ret; + probe_fail: _mt6660_chip_power_on(chip, 0); mutex_destroy(&chip->io_lock); return ret; } -static int mt6660_i2c_remove(struct i2c_client *client) +static void mt6660_i2c_remove(struct i2c_client *client) { struct mt6660_chip *chip = i2c_get_clientdata(client); pm_runtime_disable(chip->dev); pm_runtime_set_suspended(chip->dev); mutex_destroy(&chip->io_lock); - return 0; } static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev) @@ -568,7 +570,7 @@ static struct i2c_driver mt6660_i2c_driver = { .of_match_table = of_match_ptr(mt6660_of_id), .pm = &mt6660_dev_pm_ops, }, - .probe = mt6660_i2c_probe, + .probe_new = mt6660_i2c_probe, .remove = mt6660_i2c_remove, .id_table = mt6660_i2c_id, }; diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c index 2b66e3f7a8b7..ad4dce9e5080 100644 --- a/sound/soc/codecs/nau8315.c +++ b/sound/soc/codecs/nau8315.c @@ -93,7 +93,6 @@ static const struct snd_soc_component_driver nau8315_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops nau8315_dai_ops = { diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index ace96995fedc..0626d5694c22 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -357,17 +357,32 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = { {"AIFTX", NULL, "Digital CH4 Mux"}, }; -static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr) +static const struct nau8540_osr_attr * +nau8540_get_osr(struct nau8540 *nau8540) { + unsigned int osr; + + regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr); + osr &= NAU8540_ADC_OSR_MASK; if (osr >= ARRAY_SIZE(osr_adc_sel)) - return -EINVAL; + return NULL; + return &osr_adc_sel[osr]; +} + +static int nau8540_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component); + const struct nau8540_osr_attr *osr; - if (rate * osr > CLK_ADC_MAX) { - dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n"); + osr = nau8540_get_osr(nau8540); + if (!osr || !osr->osr) return -EINVAL; - } - return 0; + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + 0, CLK_ADC_MAX / osr->osr); } static int nau8540_hw_params(struct snd_pcm_substream *substream, @@ -375,7 +390,8 @@ static int nau8540_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component); - unsigned int val_len = 0, osr; + unsigned int val_len = 0; + const struct nau8540_osr_attr *osr; /* CLK_ADC = OSR * FS * ADC clock frequency is defined as Over Sampling Rate (OSR) @@ -383,13 +399,14 @@ static int nau8540_hw_params(struct snd_pcm_substream *substream, * values must be selected such that the maximum frequency is less * than 6.144 MHz. */ - regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr); - osr &= NAU8540_ADC_OSR_MASK; - if (nau8540_clock_check(nau8540, params_rate(params), osr)) + osr = nau8540_get_osr(nau8540); + if (!osr || !osr->osr) + return -EINVAL; + if (params_rate(params) * osr->osr > CLK_ADC_MAX) return -EINVAL; regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC, NAU8540_CLK_ADC_SRC_MASK, - osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT); + osr->clk_src << NAU8540_CLK_ADC_SRC_SFT); switch (params_width(params)) { case 16: @@ -515,6 +532,7 @@ static int nau8540_set_tdm_slot(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops nau8540_dai_ops = { + .startup = nau8540_dai_startup, .hw_params = nau8540_hw_params, .set_fmt = nau8540_set_fmt, .set_tdm_slot = nau8540_set_tdm_slot, @@ -806,7 +824,6 @@ static const struct snd_soc_component_driver nau8540_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config nau8540_regmap_config = { @@ -823,8 +840,7 @@ static const struct regmap_config nau8540_regmap_config = { .num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults), }; -static int nau8540_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8540_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8540 *nau8540 = dev_get_platdata(dev); @@ -874,7 +890,7 @@ static struct i2c_driver nau8540_i2c_driver = { .name = "nau8540", .of_match_table = of_match_ptr(nau8540_of_ids), }, - .probe = nau8540_i2c_probe, + .probe_new = nau8540_i2c_probe, .id_table = nau8540_i2c_ids, }; module_i2c_driver(nau8540_i2c_driver); diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 13676b544f58..ccb512c21d74 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -866,11 +866,9 @@ static const struct snd_soc_component_driver nau8810_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int nau8810_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8810_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8810 *nau8810 = dev_get_platdata(dev); @@ -916,7 +914,7 @@ static struct i2c_driver nau8810_i2c_driver = { .name = "nau8810", .of_match_table = of_match_ptr(nau8810_of_match), }, - .probe = nau8810_i2c_probe, + .probe_new = nau8810_i2c_probe, .id_table = nau8810_i2c_id, }; diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index 2de818377484..4a72b94e8410 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -29,11 +29,14 @@ #define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 +#define NAU8821_BUTTON SND_JACK_BTN_0 + /* the maximum frequency of CLK_ADC and CLK_DAC */ #define CLK_DA_AD_MAX 6144000 static int nau8821_configure_sysclk(struct nau8821 *nau8821, int clk_id, unsigned int freq); +static bool nau8821_is_jack_inserted(struct regmap *regmap); struct nau8821_fll { int mclk_src; @@ -493,7 +496,33 @@ static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w, return 0; } +static int system_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + dev_dbg(nau8821->dev, "system clock control : POWER OFF\n"); + /* Set clock source to disable or internal clock before the + * playback or capture end. Codec needs clock for Jack + * detection and button press if jack inserted; otherwise, + * the clock should be closed. + */ + if (nau8821_is_jack_inserted(nau8821->regmap)) { + nau8821_configure_sysclk(nau8821, + NAU8821_CLK_INTERNAL, 0); + } else { + nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0); + } + } + return 0; +} + static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0, + system_clock_control, SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8821_R74_MIC_BIAS, NAU8821_MICBIAS_POWERUP_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0, @@ -605,6 +634,9 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = { {"AIFTX", NULL, "ADCL Digital path"}, {"AIFTX", NULL, "ADCR Digital path"}, + {"AIFTX", NULL, "System Clock"}, + {"AIFRX", NULL, "System Clock"}, + {"DDACL", NULL, "AIFRX"}, {"DDACR", NULL, "AIFRX"}, @@ -638,28 +670,40 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = { {"HPOR", NULL, "Class G"}, }; -static int nau8821_clock_check(struct nau8821 *nau8821, - int stream, int rate, int osr) +static const struct nau8821_osr_attr * +nau8821_get_osr(struct nau8821 *nau8821, int stream) { - int osrate = 0; + unsigned int osr; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr); + osr &= NAU8821_DAC_OVERSAMPLE_MASK; if (osr >= ARRAY_SIZE(osr_dac_sel)) - return -EINVAL; - osrate = osr_dac_sel[osr].osr; + return NULL; + return &osr_dac_sel[osr]; } else { + regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr); + osr &= NAU8821_ADC_SYNC_DOWN_MASK; if (osr >= ARRAY_SIZE(osr_adc_sel)) - return -EINVAL; - osrate = osr_adc_sel[osr].osr; + return NULL; + return &osr_adc_sel[osr]; } +} - if (!osrate || rate * osrate > CLK_DA_AD_MAX) { - dev_err(nau8821->dev, - "exceed the maximum frequency of CLK_ADC or CLK_DAC"); +static int nau8821_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); + const struct nau8821_osr_attr *osr; + + osr = nau8821_get_osr(nau8821, substream->stream); + if (!osr || !osr->osr) return -EINVAL; - } - return 0; + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + 0, CLK_DA_AD_MAX / osr->osr); } static int nau8821_hw_params(struct snd_pcm_substream *substream, @@ -667,7 +711,8 @@ static int nau8821_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); - unsigned int val_len = 0, osr, ctrl_val, bclk_fs, clk_div; + unsigned int val_len = 0, ctrl_val, bclk_fs, clk_div; + const struct nau8821_osr_attr *osr; nau8821->fs = params_rate(params); /* CLK_DAC or CLK_ADC = OSR * FS @@ -676,27 +721,19 @@ static int nau8821_hw_params(struct snd_pcm_substream *substream, * values must be selected such that the maximum frequency is less * than 6.144 MHz. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr); - osr &= NAU8821_DAC_OVERSAMPLE_MASK; - if (nau8821_clock_check(nau8821, substream->stream, - nau8821->fs, osr)) { - return -EINVAL; - } + osr = nau8821_get_osr(nau8821, substream->stream); + if (!osr || !osr->osr) + return -EINVAL; + if (nau8821->fs * osr->osr > CLK_DA_AD_MAX) + return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER, NAU8821_CLK_DAC_SRC_MASK, - osr_dac_sel[osr].clk_src << NAU8821_CLK_DAC_SRC_SFT); - } else { - regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr); - osr &= NAU8821_ADC_SYNC_DOWN_MASK; - if (nau8821_clock_check(nau8821, substream->stream, - nau8821->fs, osr)) { - return -EINVAL; - } + osr->clk_src << NAU8821_CLK_DAC_SRC_SFT); + else regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER, NAU8821_CLK_ADC_SRC_MASK, - osr_adc_sel[osr].clk_src << NAU8821_CLK_ADC_SRC_SFT); - } + osr->clk_src << NAU8821_CLK_ADC_SRC_SFT); /* make BCLK and LRC divde configuration if the codec as master. */ regmap_read(nau8821->regmap, NAU8821_R1D_I2S_PCM_CTRL2, &ctrl_val); @@ -811,9 +848,11 @@ static int nau8821_digital_mute(struct snd_soc_dai *dai, int mute, } static const struct snd_soc_dai_ops nau8821_dai_ops = { + .startup = nau8821_dai_startup, .hw_params = nau8821_hw_params, .set_fmt = nau8821_set_dai_fmt, .mute_stream = nau8821_digital_mute, + .no_capture_mute = 1, }; #define NAU8821_RATES SNDRV_PCM_RATE_8000_192000 @@ -910,6 +949,20 @@ static void nau8821_eject_jack(struct nau8821 *nau8821) /* Recover to normal channel input */ regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE, NAU8821_ADC_R_SRC_EN, 0); + if (nau8821->key_enable) { + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN); + regmap_update_bits(regmap, + NAU8821_R12_INTERRUPT_DIS_CTRL, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS); + } + } static void nau8821_jdet_work(struct work_struct *work) @@ -939,6 +992,15 @@ static void nau8821_jdet_work(struct work_struct *work) */ regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE, NAU8821_ADC_R_SRC_EN, NAU8821_ADC_R_SRC_EN); + if (nau8821->key_enable) { + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, + NAU8821_IRQ_KEY_RELEASE_EN | + NAU8821_IRQ_KEY_PRESS_EN, 0); + regmap_update_bits(regmap, + NAU8821_R12_INTERRUPT_DIS_CTRL, + NAU8821_IRQ_KEY_RELEASE_DIS | + NAU8821_IRQ_KEY_PRESS_DIS, 0); + } } else { dev_dbg(nau8821->dev, "Headphone connected\n"); event |= SND_JACK_HEADPHONE; @@ -998,6 +1060,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data) nau8821_eject_jack(nau8821); event_mask |= SND_JACK_HEADSET; clear_irq = NAU8821_JACK_EJECT_IRQ_MASK; + } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) { + event |= NAU8821_BUTTON; + event_mask |= NAU8821_BUTTON; + clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ; + } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) { + event_mask = NAU8821_BUTTON; + clear_irq = NAU8821_KEY_RELEASE_IRQ; } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) == NAU8821_JACK_INSERT_DETECTED) { regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1, @@ -1429,7 +1498,6 @@ static const struct snd_soc_component_driver nau8821_component_driver = { .dapm_routes = nau8821_dapm_routes, .num_dapm_routes = ARRAY_SIZE(nau8821_dapm_routes), .suspend_bias_off = 1, - .non_legacy_dai_naming = 1, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, @@ -1489,6 +1557,7 @@ static void nau8821_print_device_properties(struct nau8821 *nau8821) nau8821->jack_eject_debounce); dev_dbg(dev, "dmic-clk-threshold: %d\n", nau8821->dmic_clk_threshold); + dev_dbg(dev, "key_enable: %d\n", nau8821->key_enable); } static int nau8821_read_device_properties(struct device *dev, @@ -1502,6 +1571,8 @@ static int nau8821_read_device_properties(struct device *dev, "nuvoton,jkdet-pull-enable"); nau8821->jkdet_pull_up = device_property_read_bool(dev, "nuvoton,jkdet-pull-up"); + nau8821->key_enable = device_property_read_bool(dev, + "nuvoton,key-enable"); ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity", &nau8821->jkdet_polarity); if (ret) @@ -1625,8 +1696,7 @@ static int nau8821_setup_irq(struct nau8821 *nau8821) return 0; } -static int nau8821_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8821_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8821 *nau8821 = dev_get_platdata(&i2c->dev); @@ -1665,15 +1735,6 @@ static int nau8821_i2c_probe(struct i2c_client *i2c, return ret; } -static int nau8821_i2c_remove(struct i2c_client *i2c_client) -{ - struct nau8821 *nau8821 = i2c_get_clientdata(i2c_client); - - devm_free_irq(nau8821->dev, nau8821->irq, nau8821); - - return 0; -} - static const struct i2c_device_id nau8821_i2c_ids[] = { { "nau8821", 0 }, { } @@ -1702,8 +1763,7 @@ static struct i2c_driver nau8821_driver = { .of_match_table = of_match_ptr(nau8821_of_ids), .acpi_match_table = ACPI_PTR(nau8821_acpi_match), }, - .probe = nau8821_i2c_probe, - .remove = nau8821_i2c_remove, + .probe_new = nau8821_i2c_probe, .id_table = nau8821_i2c_ids, }; module_i2c_driver(nau8821_driver); diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index a92edfeb9d3a..c44251f54d48 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -525,6 +525,7 @@ struct nau8821 { int jack_eject_debounce; int fs; int dmic_clk_threshold; + int key_enable; }; int nau8821_enable_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 58123390c7a3..1aef281a9972 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -726,6 +726,17 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, struct nau8822_pll *pll_param = &nau8822->pll; int ret, fs; + if (freq_in == pll_param->freq_in && + freq_out == pll_param->freq_out) + return 0; + + if (freq_out == 0) { + dev_dbg(component->dev, "PLL disabled\n"); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); + return 0; + } + fs = freq_out / 256; ret = nau8822_calc_pll(freq_in, fs, pll_param); @@ -741,6 +752,8 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_param->mclk_scaler, pll_param->pre_factor); snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); + snd_soc_component_update_bits(component, NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | pll_param->pll_int); @@ -757,6 +770,11 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); snd_soc_component_update_bits(component, NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON); + + pll_param->freq_in = freq_in; + pll_param->freq_out = freq_out; return 0; } @@ -1065,7 +1083,6 @@ static const struct snd_soc_component_driver soc_component_dev_nau8822 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config nau8822_regmap_config = { @@ -1083,8 +1100,7 @@ static const struct regmap_config nau8822_regmap_config = { .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), }; -static int nau8822_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8822_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8822 *nau8822 = dev_get_platdata(dev); @@ -1141,7 +1157,7 @@ static struct i2c_driver nau8822_i2c_driver = { .name = "nau8822", .of_match_table = of_match_ptr(nau8822_of_match), }, - .probe = nau8822_i2c_probe, + .probe_new = nau8822_i2c_probe, .id_table = nau8822_i2c_id, }; module_i2c_driver(nau8822_i2c_driver); diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index 489191ff187e..547ec057f853 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -90,6 +90,9 @@ #define NAU8822_REFIMP_3K 0x3 #define NAU8822_IOBUF_EN (0x1 << 2) #define NAU8822_ABIAS_EN (0x1 << 3) +#define NAU8822_PLL_EN_MASK (0x1 << 5) +#define NAU8822_PLL_ON (0x1 << 5) +#define NAU8822_PLL_OFF (0x0 << 5) /* NAU8822_REG_AUDIO_INTERFACE (0x4) */ #define NAU8822_AIFMT_MASK (0x3 << 3) @@ -195,6 +198,8 @@ struct nau8822_pll { int mclk_scaler; int pll_frac; int pll_int; + int freq_in; + int freq_out; }; /* Codec Private Data */ diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index d0dd1542f78a..4f19fd9b65d1 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -901,7 +901,10 @@ static void nau8824_jdet_work(struct work_struct *work) NAU8824_IRQ_KEY_RELEASE_DIS | NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0); - nau8824_sema_release(nau8824); + if (nau8824->resume_lock) { + nau8824_sema_release(nau8824); + nau8824->resume_lock = false; + } } static void nau8824_setup_auto_irq(struct nau8824 *nau8824) @@ -966,7 +969,10 @@ static irqreturn_t nau8824_interrupt(int irq, void *data) /* release semaphore held after resume, * and cancel jack detection */ - nau8824_sema_release(nau8824); + if (nau8824->resume_lock) { + nau8824_sema_release(nau8824); + nau8824->resume_lock = false; + } cancel_work_sync(&nau8824->jdet_work); } else if (active_irq & NAU8824_KEY_SHORT_PRESS_IRQ) { int key_status, button_pressed; @@ -1014,27 +1020,42 @@ static irqreturn_t nau8824_interrupt(int irq, void *data) return IRQ_HANDLED; } -static int nau8824_clock_check(struct nau8824 *nau8824, - int stream, int rate, int osr) +static const struct nau8824_osr_attr * +nau8824_get_osr(struct nau8824 *nau8824, int stream) { - int osrate; + unsigned int osr; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_read(nau8824->regmap, + NAU8824_REG_DAC_FILTER_CTRL_1, &osr); + osr &= NAU8824_DAC_OVERSAMPLE_MASK; if (osr >= ARRAY_SIZE(osr_dac_sel)) - return -EINVAL; - osrate = osr_dac_sel[osr].osr; + return NULL; + return &osr_dac_sel[osr]; } else { + regmap_read(nau8824->regmap, + NAU8824_REG_ADC_FILTER_CTRL, &osr); + osr &= NAU8824_ADC_SYNC_DOWN_MASK; if (osr >= ARRAY_SIZE(osr_adc_sel)) - return -EINVAL; - osrate = osr_adc_sel[osr].osr; + return NULL; + return &osr_adc_sel[osr]; } +} + +static int nau8824_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); + const struct nau8824_osr_attr *osr; - if (!osrate || rate * osr > CLK_DA_AD_MAX) { - dev_err(nau8824->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); + osr = nau8824_get_osr(nau8824, substream->stream); + if (!osr || !osr->osr) return -EINVAL; - } - return 0; + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + 0, CLK_DA_AD_MAX / osr->osr); } static int nau8824_hw_params(struct snd_pcm_substream *substream, @@ -1042,7 +1063,9 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); - unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div; + unsigned int val_len = 0, ctrl_val, bclk_fs, bclk_div; + const struct nau8824_osr_attr *osr; + int err = -EINVAL; nau8824_sema_acquire(nau8824, HZ); @@ -1053,27 +1076,19 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, * than 6.144 MHz. */ nau8824->fs = params_rate(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_read(nau8824->regmap, - NAU8824_REG_DAC_FILTER_CTRL_1, &osr); - osr &= NAU8824_DAC_OVERSAMPLE_MASK; - if (nau8824_clock_check(nau8824, substream->stream, - nau8824->fs, osr)) - return -EINVAL; + osr = nau8824_get_osr(nau8824, substream->stream); + if (!osr || !osr->osr) + goto error; + if (nau8824->fs * osr->osr > CLK_DA_AD_MAX) + goto error; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER, NAU8824_CLK_DAC_SRC_MASK, - osr_dac_sel[osr].clk_src << NAU8824_CLK_DAC_SRC_SFT); - } else { - regmap_read(nau8824->regmap, - NAU8824_REG_ADC_FILTER_CTRL, &osr); - osr &= NAU8824_ADC_SYNC_DOWN_MASK; - if (nau8824_clock_check(nau8824, substream->stream, - nau8824->fs, osr)) - return -EINVAL; + osr->clk_src << NAU8824_CLK_DAC_SRC_SFT); + else regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER, NAU8824_CLK_ADC_SRC_MASK, - osr_adc_sel[osr].clk_src << NAU8824_CLK_ADC_SRC_SFT); - } + osr->clk_src << NAU8824_CLK_ADC_SRC_SFT); /* make BCLK and LRC divde configuration if the codec as master. */ regmap_read(nau8824->regmap, @@ -1090,7 +1105,7 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, else if (bclk_fs <= 256) bclk_div = 0; else - return -EINVAL; + goto error; regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_2, NAU8824_I2S_LRC_DIV_MASK | NAU8824_I2S_BLK_DIV_MASK, @@ -1111,15 +1126,17 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, val_len |= NAU8824_I2S_DL_32; break; default: - return -EINVAL; + goto error; } regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1, NAU8824_I2S_DL_MASK, val_len); + err = 0; + error: nau8824_sema_release(nau8824); - return 0; + return err; } static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -1128,8 +1145,6 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); unsigned int ctrl1_val = 0, ctrl2_val = 0; - nau8824_sema_acquire(nau8824, HZ); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: ctrl2_val |= NAU8824_I2S_MS_MASTER; @@ -1171,6 +1186,8 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } + nau8824_sema_acquire(nau8824, HZ); + regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1, NAU8824_I2S_DF_MASK | NAU8824_I2S_BP_MASK | NAU8824_I2S_PCMB_EN, ctrl1_val); @@ -1513,6 +1530,7 @@ static int __maybe_unused nau8824_suspend(struct snd_soc_component *component) static int __maybe_unused nau8824_resume(struct snd_soc_component *component) { struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); + int ret; regcache_cache_only(nau8824->regmap, false); regcache_sync(nau8824->regmap); @@ -1520,7 +1538,10 @@ static int __maybe_unused nau8824_resume(struct snd_soc_component *component) /* Hold semaphore to postpone playback happening * until jack detection done. */ - nau8824_sema_acquire(nau8824, 0); + nau8824->resume_lock = true; + ret = nau8824_sema_acquire(nau8824, 0); + if (ret) + nau8824->resume_lock = false; enable_irq(nau8824->irq); } @@ -1544,10 +1565,10 @@ static const struct snd_soc_component_driver nau8824_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops nau8824_dai_ops = { + .startup = nau8824_dai_startup, .hw_params = nau8824_hw_params, .set_fmt = nau8824_set_fmt, .set_tdm_slot = nau8824_set_tdm_slot, @@ -1910,8 +1931,7 @@ const char *nau8824_components(void) } EXPORT_SYMBOL_GPL(nau8824_components); -static int nau8824_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8824_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8824 *nau8824 = dev_get_platdata(dev); @@ -1930,6 +1950,7 @@ static int nau8824_i2c_probe(struct i2c_client *i2c, nau8824->regmap = devm_regmap_init_i2c(i2c, &nau8824_regmap_config); if (IS_ERR(nau8824->regmap)) return PTR_ERR(nau8824->regmap); + nau8824->resume_lock = false; nau8824->dev = dev; nau8824->irq = i2c->irq; sema_init(&nau8824->jd_sem, 1); @@ -1985,7 +2006,7 @@ static struct i2c_driver nau8824_i2c_driver = { .of_match_table = of_match_ptr(nau8824_of_ids), .acpi_match_table = ACPI_PTR(nau8824_acpi_match), }, - .probe = nau8824_i2c_probe, + .probe_new = nau8824_i2c_probe, .id_table = nau8824_i2c_ids, }; module_i2c_driver(nau8824_i2c_driver); diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h index de4bae8281d0..5fcfc43dfc85 100644 --- a/sound/soc/codecs/nau8824.h +++ b/sound/soc/codecs/nau8824.h @@ -436,6 +436,7 @@ struct nau8824 { struct semaphore jd_sem; int fs; int irq; + int resume_lock; int micbias_voltage; int vref_impedance; int jkdet_polarity; diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7734bc35ab21..3eac7c92df88 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1247,27 +1247,42 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = { {"HPOR", NULL, "Class G"}, }; -static int nau8825_clock_check(struct nau8825 *nau8825, - int stream, int rate, int osr) +static const struct nau8825_osr_attr * +nau8825_get_osr(struct nau8825 *nau8825, int stream) { - int osrate; + unsigned int osr; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_read(nau8825->regmap, + NAU8825_REG_DAC_CTRL1, &osr); + osr &= NAU8825_DAC_OVERSAMPLE_MASK; if (osr >= ARRAY_SIZE(osr_dac_sel)) - return -EINVAL; - osrate = osr_dac_sel[osr].osr; + return NULL; + return &osr_dac_sel[osr]; } else { + regmap_read(nau8825->regmap, + NAU8825_REG_ADC_RATE, &osr); + osr &= NAU8825_ADC_SYNC_DOWN_MASK; if (osr >= ARRAY_SIZE(osr_adc_sel)) - return -EINVAL; - osrate = osr_adc_sel[osr].osr; + return NULL; + return &osr_adc_sel[osr]; } +} + +static int nau8825_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); + const struct nau8825_osr_attr *osr; - if (!osrate || rate * osr > CLK_DA_AD_MAX) { - dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); + osr = nau8825_get_osr(nau8825, substream->stream); + if (!osr || !osr->osr) return -EINVAL; - } - return 0; + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + 0, CLK_DA_AD_MAX / osr->osr); } static int nau8825_hw_params(struct snd_pcm_substream *substream, @@ -1276,7 +1291,9 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); - unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div; + unsigned int val_len = 0, ctrl_val, bclk_fs, bclk_div; + const struct nau8825_osr_attr *osr; + int err = -EINVAL; nau8825_sema_acquire(nau8825, 3 * HZ); @@ -1286,29 +1303,19 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, * values must be selected such that the maximum frequency is less * than 6.144 MHz. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); - osr &= NAU8825_DAC_OVERSAMPLE_MASK; - if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) { - nau8825_sema_release(nau8825); - return -EINVAL; - } + osr = nau8825_get_osr(nau8825, substream->stream); + if (!osr || !osr->osr) + goto error; + if (params_rate(params) * osr->osr > CLK_DA_AD_MAX) + goto error; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_DAC_SRC_MASK, - osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); - } else { - regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); - osr &= NAU8825_ADC_SYNC_DOWN_MASK; - if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) { - nau8825_sema_release(nau8825); - return -EINVAL; - } + osr->clk_src << NAU8825_CLK_DAC_SRC_SFT); + else regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_ADC_SRC_MASK, - osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); - } + osr->clk_src << NAU8825_CLK_ADC_SRC_SFT); /* make BCLK and LRC divde configuration if the codec as master. */ regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, &ctrl_val); @@ -1321,10 +1328,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, bclk_div = 1; else if (bclk_fs <= 128) bclk_div = 0; - else { - nau8825_sema_release(nau8825); - return -EINVAL; - } + else + goto error; regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div); @@ -1344,17 +1349,18 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, val_len |= NAU8825_I2S_DL_32; break; default: - nau8825_sema_release(nau8825); - return -EINVAL; + goto error; } regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK, val_len); + err = 0; + error: /* Release the semaphore. */ nau8825_sema_release(nau8825); - return 0; + return err; } static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) @@ -1419,9 +1425,107 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } +/** + * nau8825_set_tdm_slot - configure DAI TDM. + * @dai: DAI + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. + * + * Configures a DAI for TDM operation. Support TDM 4/8 slots. + * The limitation is DAC and ADC need shift 4 slots at 8 slots mode. + */ +static int nau8825_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); + unsigned int ctrl_val = 0, ctrl_offset = 0, value = 0, dac_s, adc_s; + + if (slots != 4 && slots != 8) { + dev_err(nau8825->dev, "Only support 4 or 8 slots!\n"); + return -EINVAL; + } + + /* The driver is limited to 1-channel for ADC, and 2-channel for DAC on TDM mode */ + if (hweight_long((unsigned long) tx_mask) != 1 || + hweight_long((unsigned long) rx_mask) != 2) { + dev_err(nau8825->dev, + "The limitation is 1-channel for ADC, and 2-channel for DAC on TDM mode.\n"); + return -EINVAL; + } + + if (((tx_mask & 0xf) && (tx_mask & 0xf0)) || + ((rx_mask & 0xf) && (rx_mask & 0xf0)) || + ((tx_mask & 0xf) && (rx_mask & 0xf0)) || + ((rx_mask & 0xf) && (tx_mask & 0xf0))) { + dev_err(nau8825->dev, + "Slot assignment of DAC and ADC need to set same interval.\n"); + return -EINVAL; + } + + /* The offset of fixed 4 slots for 8 slots support */ + if (rx_mask & 0xf0) { + regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, + NAU8825_I2S_PCM_TS_EN_MASK, NAU8825_I2S_PCM_TS_EN); + regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, &value); + ctrl_val |= NAU8825_TDM_OFFSET_EN; + ctrl_offset = 4 * slot_width; + if (!(value & NAU8825_I2S_PCMB_MASK)) + ctrl_offset += 1; + dac_s = (rx_mask & 0xf0) >> 4; + adc_s = fls((tx_mask & 0xf0) >> 4); + } else { + dac_s = rx_mask & 0xf; + adc_s = fls(tx_mask & 0xf); + } + + ctrl_val |= NAU8825_TDM_MODE; + + switch (dac_s) { + case 0x3: + ctrl_val |= 1 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x5: + ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x6: + ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x9: + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0xa: + ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0xc: + ctrl_val |= 2 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + default: + return -EINVAL; + } + + ctrl_val |= adc_s - 1; + + regmap_update_bits(nau8825->regmap, NAU8825_REG_TDM_CTRL, + NAU8825_TDM_MODE | NAU8825_TDM_OFFSET_EN | + NAU8825_TDM_DACL_RX_MASK | NAU8825_TDM_DACR_RX_MASK | + NAU8825_TDM_TX_MASK, ctrl_val); + regmap_update_bits(nau8825->regmap, NAU8825_REG_LEFT_TIME_SLOT, + NAU8825_TSLOT_L0_MASK, ctrl_offset); + + return 0; +} + static const struct snd_soc_dai_ops nau8825_dai_ops = { + .startup = nau8825_dai_startup, .hw_params = nau8825_hw_params, .set_fmt = nau8825_set_dai_fmt, + .set_tdm_slot = nau8825_set_tdm_slot, }; #define NAU8825_RATES SNDRV_PCM_RATE_8000_192000 @@ -1440,7 +1544,7 @@ static struct snd_soc_dai_driver nau8825_dai = { .capture = { .stream_name = "Capture", .channels_min = 1, - .channels_max = 1, + .channels_max = 2, /* Only 1 channel of data */ .rates = NAU8825_RATES, .formats = NAU8825_FORMATS, }, @@ -1976,6 +2080,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825) /* Disable short Frame Sync detection logic */ regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT, NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET); + /* ADCDAT IO drive strength control */ + regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_ADCOUT_DS_MASK, + nau8825->adcout_ds << NAU8825_ADCOUT_DS_SFT); } static const struct regmap_config nau8825_regmap_config = { @@ -2478,7 +2586,6 @@ static const struct snd_soc_component_driver nau8825_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void nau8825_reset_chip(struct regmap *regmap) @@ -2515,6 +2622,7 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) nau8825->jack_eject_debounce); dev_dbg(dev, "crosstalk-enable: %d\n", nau8825->xtalk_enable); + dev_dbg(dev, "adcout-drive-strong: %d\n", nau8825->adcout_ds); } static int nau8825_read_device_properties(struct device *dev, @@ -2581,6 +2689,7 @@ static int nau8825_read_device_properties(struct device *dev, nau8825->jack_eject_debounce = 0; nau8825->xtalk_enable = device_property_read_bool(dev, "nuvoton,crosstalk-enable"); + nau8825->adcout_ds = device_property_read_bool(dev, "nuvoton,adcout-drive-strong"); nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { @@ -2613,8 +2722,7 @@ static int nau8825_setup_irq(struct nau8825 *nau8825) return 0; } -static int nau8825_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int nau8825_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct nau8825 *nau8825 = dev_get_platdata(&i2c->dev); @@ -2670,10 +2778,8 @@ static int nau8825_i2c_probe(struct i2c_client *i2c, &nau8825_dai, 1); } -static int nau8825_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void nau8825_i2c_remove(struct i2c_client *client) +{} static const struct i2c_device_id nau8825_i2c_ids[] = { { "nau8825", 0 }, @@ -2703,7 +2809,7 @@ static struct i2c_driver nau8825_driver = { .of_match_table = of_match_ptr(nau8825_of_ids), .acpi_match_table = ACPI_PTR(nau8825_acpi_match), }, - .probe = nau8825_i2c_probe, + .probe_new = nau8825_i2c_probe, .remove = nau8825_i2c_remove, .id_table = nau8825_i2c_ids, }; diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 887bbff03ec6..d84191a7beb2 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -225,6 +225,15 @@ #define NAU8825_JKDET_PULL_EN (1 << 9) /* 0 - enable pull, 1 - disable */ #define NAU8825_JKDET_OUTPUT_EN (1 << 8) /* 0 - enable input, 1 - enable output */ +/* TDM_CTRL (0x1b) */ +#define NAU8825_TDM_MODE (0x1 << 15) +#define NAU8825_TDM_OFFSET_EN (0x1 << 14) +#define NAU8825_TDM_DACL_RX_SFT 6 +#define NAU8825_TDM_DACL_RX_MASK (0x3 << NAU8825_TDM_DACL_RX_SFT) +#define NAU8825_TDM_DACR_RX_SFT 4 +#define NAU8825_TDM_DACR_RX_MASK (0x3 << NAU8825_TDM_DACR_RX_SFT) +#define NAU8825_TDM_TX_MASK 0x3 + /* I2S_PCM_CTRL1 (0x1c) */ #define NAU8825_I2S_BP_SFT 7 #define NAU8825_I2S_BP_MASK (1 << NAU8825_I2S_BP_SFT) @@ -249,6 +258,9 @@ #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ #define NAU8825_I2S_LRC_DIV_SFT 12 #define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT) +#define NAU8825_I2S_PCM_TS_EN_SFT 10 +#define NAU8825_I2S_PCM_TS_EN_MASK (1 << NAU8825_I2S_PCM_TS_EN_SFT) +#define NAU8825_I2S_PCM_TS_EN (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_MS_SFT 3 #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) @@ -259,6 +271,8 @@ #define NAU8825_FS_ERR_CMP_SEL_SFT 14 #define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) #define NAU8825_DIS_FS_SHORT_DET (1 << 13) +#define NAU8825_TSLOT_L0_MASK 0x3ff +#define NAU8825_TSLOT_R0_MASK 0x3ff /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 @@ -418,6 +432,8 @@ #define NAU8825_POWERUP_HP_DRV_L (1 << 0) /* CHARGE_PUMP (0x80) */ +#define NAU8825_ADCOUT_DS_SFT 12 +#define NAU8825_ADCOUT_DS_MASK (1 << NAU8825_ADCOUT_DS_SFT) #define NAU8825_JAMNODCLOW (1 << 10) #define NAU8825_POWER_DOWN_DACR (1 << 9) #define NAU8825_POWER_DOWN_DACL (1 << 8) @@ -477,6 +493,7 @@ struct nau8825 { int imp_rms[NAU8825_XTALK_IMM]; int xtalk_enable; bool xtalk_baktab_initialized; /* True if initialized. */ + bool adcout_ds; }; int nau8825_enable_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 5b78e9299c95..3591f6f53901 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -136,8 +136,8 @@ static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); - /* The PCM1681 can only be slave to all clocks */ - if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + /* The PCM1681 can only be consumer to all clocks */ + if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(component->dev, "Invalid clocking mode\n"); return -EINVAL; } @@ -290,7 +290,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1681 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id pcm1681_i2c_id[] = { @@ -299,8 +298,7 @@ static const struct i2c_device_id pcm1681_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id); -static int pcm1681_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm1681_i2c_probe(struct i2c_client *client) { int ret; struct pcm1681_private *priv; @@ -329,7 +327,7 @@ static struct i2c_driver pcm1681_i2c_driver = { .of_match_table = of_match_ptr(pcm1681_dt_ids), }, .id_table = pcm1681_i2c_id, - .probe = pcm1681_i2c_probe, + .probe_new = pcm1681_i2c_probe, }; module_i2c_driver(pcm1681_i2c_driver); diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c index 7a6be45f8149..fafe0dcbe4ea 100644 --- a/sound/soc/codecs/pcm1789-i2c.c +++ b/sound/soc/codecs/pcm1789-i2c.c @@ -12,8 +12,7 @@ #include "pcm1789.h" -static int pcm1789_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm1789_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -28,9 +27,9 @@ static int pcm1789_i2c_probe(struct i2c_client *client, return pcm1789_common_init(&client->dev, regmap); } -static int pcm1789_i2c_remove(struct i2c_client *client) +static void pcm1789_i2c_remove(struct i2c_client *client) { - return pcm1789_common_exit(&client->dev); + pcm1789_common_exit(&client->dev); } #ifdef CONFIG_OF @@ -53,7 +52,7 @@ static struct i2c_driver pcm1789_i2c_driver = { .of_match_table = of_match_ptr(pcm1789_of_match), }, .id_table = pcm1789_i2c_ids, - .probe = pcm1789_i2c_probe, + .probe_new = pcm1789_i2c_probe, .remove = pcm1789_i2c_remove, }; diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c index 620dec172ce7..3ab381e9a856 100644 --- a/sound/soc/codecs/pcm1789.c +++ b/sound/soc/codecs/pcm1789.c @@ -229,7 +229,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1789 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm1789_common_init(struct device *dev, struct regmap *regmap) @@ -259,13 +258,11 @@ int pcm1789_common_init(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(pcm1789_common_init); -int pcm1789_common_exit(struct device *dev) +void pcm1789_common_exit(struct device *dev) { struct pcm1789_private *priv = dev_get_drvdata(dev); flush_work(&priv->work); - - return 0; } EXPORT_SYMBOL_GPL(pcm1789_common_exit); diff --git a/sound/soc/codecs/pcm1789.h b/sound/soc/codecs/pcm1789.h index c446d789ed48..79439c8322b3 100644 --- a/sound/soc/codecs/pcm1789.h +++ b/sound/soc/codecs/pcm1789.h @@ -12,6 +12,6 @@ extern const struct regmap_config pcm1789_regmap_config; int pcm1789_common_init(struct device *dev, struct regmap *regmap); -int pcm1789_common_exit(struct device *dev); +void pcm1789_common_exit(struct device *dev); #endif diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c index 34a3d596f288..e20fe3a85af8 100644 --- a/sound/soc/codecs/pcm179x-i2c.c +++ b/sound/soc/codecs/pcm179x-i2c.c @@ -14,8 +14,7 @@ #include "pcm179x.h" -static int pcm179x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcm179x_i2c_probe(struct i2c_client *client) { struct regmap *regmap; int ret; @@ -50,7 +49,7 @@ static struct i2c_driver pcm179x_i2c_driver = { .of_match_table = of_match_ptr(pcm179x_of_match), }, .id_table = pcm179x_i2c_ids, - .probe = pcm179x_i2c_probe, + .probe_new = pcm179x_i2c_probe, }; module_i2c_driver(pcm179x_i2c_driver); diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index ee60373d7d25..f52ff66b6e64 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -207,7 +207,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm179x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm179x_common_init(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c index f8382b74391d..932c8d41c3ea 100644 --- a/sound/soc/codecs/pcm186x-i2c.c +++ b/sound/soc/codecs/pcm186x-i2c.c @@ -22,9 +22,18 @@ static const struct of_device_id pcm186x_of_match[] = { }; MODULE_DEVICE_TABLE(of, pcm186x_of_match); -static int pcm186x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id pcm186x_i2c_id[] = { + { "pcm1862", PCM1862 }, + { "pcm1863", PCM1863 }, + { "pcm1864", PCM1864 }, + { "pcm1865", PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id); + +static int pcm186x_i2c_probe(struct i2c_client *i2c) { + const struct i2c_device_id *id = i2c_match_id(pcm186x_i2c_id, i2c); const enum pcm186x_type type = (enum pcm186x_type)id->driver_data; int irq = i2c->irq; struct regmap *regmap; @@ -36,17 +45,8 @@ static int pcm186x_i2c_probe(struct i2c_client *i2c, return pcm186x_probe(&i2c->dev, type, irq, regmap); } -static const struct i2c_device_id pcm186x_i2c_id[] = { - { "pcm1862", PCM1862 }, - { "pcm1863", PCM1863 }, - { "pcm1864", PCM1864 }, - { "pcm1865", PCM1865 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id); - static struct i2c_driver pcm186x_i2c_driver = { - .probe = pcm186x_i2c_probe, + .probe_new = pcm186x_i2c_probe, .id_table = pcm186x_i2c_id, .driver = { .name = "pcm186x", diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index b8845f45549e..dd21803ba13c 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -39,7 +39,7 @@ struct pcm186x_priv { unsigned int sysclk; unsigned int tdm_offset; bool is_tdm_mode; - bool is_master_mode; + bool is_provider_mode; }; static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0); @@ -340,8 +340,8 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream, PCM186X_PCM_CFG_TDM_LRCK_MODE); } - /* Only configure clock dividers in master mode. */ - if (priv->is_master_mode) { + /* Only configure clock dividers in provider mode. */ + if (priv->is_provider_mode) { div_bck = priv->sysclk / (div_lrck * rate); dev_dbg(component->dev, @@ -364,18 +364,17 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format) dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format); - /* set master/slave audio interface */ - switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: if (!priv->sysclk) { - dev_err(component->dev, "operating in master mode requires sysclock to be configured\n"); + dev_err(component->dev, "operating in provider mode requires sysclock to be configured\n"); return -EINVAL; } clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE; - priv->is_master_mode = true; + priv->is_provider_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFS: - priv->is_master_mode = false; + case SND_SOC_DAIFMT_CBC_CFC: + priv->is_provider_mode = false; break; default: dev_err(component->dev, "Invalid DAI master/slave interface\n"); @@ -535,19 +534,14 @@ static int pcm186x_power_on(struct snd_soc_component *component) static int pcm186x_power_off(struct snd_soc_component *component) { struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component); - int ret; snd_soc_component_update_bits(component, PCM186X_POWER_CTRL, PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN); regcache_cache_only(priv->regmap, true); - ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); - if (ret) - return ret; - - return 0; } static int pcm186x_set_bias_level(struct snd_soc_component *component, @@ -584,7 +578,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { @@ -599,7 +592,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool pcm186x_volatile(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index aef40ec40aa1..09c6c1326833 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -102,7 +102,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm3008 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pcm3008_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c index abcdeb922201..2388098eeca3 100644 --- a/sound/soc/codecs/pcm3060-i2c.c +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -10,8 +10,7 @@ #include "pcm3060.h" -static int pcm3060_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm3060_i2c_probe(struct i2c_client *i2c) { struct pcm3060_priv *priv; @@ -50,7 +49,7 @@ static struct i2c_driver pcm3060_i2c_driver = { #endif /* CONFIG_OF */ }, .id_table = pcm3060_i2c_id, - .probe = pcm3060_i2c_probe, + .probe_new = pcm3060_i2c_probe, }; module_i2c_driver(pcm3060_i2c_driver); diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index b2358069cf9b..586ec8c7246c 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -68,15 +68,15 @@ static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - priv->dai[dai->id].is_master = true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + priv->dai[dai->id].is_provider = true; break; - case SND_SOC_DAIFMT_CBS_CFS: - priv->dai[dai->id].is_master = false; + case SND_SOC_DAIFMT_CBC_CFC: + priv->dai[dai->id].is_provider = false; break; default: - dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt); + dev_err(comp->dev, "unsupported DAI mode: 0x%x\n", fmt); return -EINVAL; } @@ -116,7 +116,7 @@ static int pcm3060_hw_params(struct snd_pcm_substream *substream, unsigned int reg; unsigned int val; - if (!priv->dai[dai->id].is_master) { + if (!priv->dai[dai->id].is_provider) { val = PCM3060_REG_MS_S; goto val_ready; } @@ -255,6 +255,7 @@ static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), .dapm_routes = pcm3060_dapm_map, .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), + .endianness = 1, }; /* regmap */ diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h index 18d51e5dac2c..5e1185e7b03d 100644 --- a/sound/soc/codecs/pcm3060.h +++ b/sound/soc/codecs/pcm3060.h @@ -23,7 +23,7 @@ extern const struct regmap_config pcm3060_regmap; #define PCM3060_CLK2 2 struct pcm3060_priv_dai { - bool is_master; + bool is_provider; unsigned int sclk_freq; }; diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c index 1f75933e74fa..a0eec82e9872 100644 --- a/sound/soc/codecs/pcm3168a-i2c.c +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -15,8 +15,7 @@ #include "pcm3168a.h" -static int pcm3168a_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm3168a_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -27,11 +26,9 @@ static int pcm3168a_i2c_probe(struct i2c_client *i2c, return pcm3168a_probe(&i2c->dev, regmap); } -static int pcm3168a_i2c_remove(struct i2c_client *i2c) +static void pcm3168a_i2c_remove(struct i2c_client *i2c) { pcm3168a_remove(&i2c->dev); - - return 0; } static const struct i2c_device_id pcm3168a_i2c_id[] = { @@ -47,7 +44,7 @@ static const struct of_device_id pcm3168a_of_match[] = { MODULE_DEVICE_TABLE(of, pcm3168a_of_match); static struct i2c_driver pcm3168a_i2c_driver = { - .probe = pcm3168a_i2c_probe, + .probe_new = pcm3168a_i2c_probe, .remove = pcm3168a_i2c_remove, .id_table = pcm3168a_i2c_id, .driver = { diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c index ecd379f308e6..b5b08046f545 100644 --- a/sound/soc/codecs/pcm3168a-spi.c +++ b/sound/soc/codecs/pcm3168a-spi.c @@ -26,11 +26,9 @@ static int pcm3168a_spi_probe(struct spi_device *spi) return pcm3168a_probe(&spi->dev, regmap); } -static int pcm3168a_spi_remove(struct spi_device *spi) +static void pcm3168a_spi_remove(struct spi_device *spi) { pcm3168a_remove(&spi->dev); - - return 0; } static const struct spi_device_id pcm3168a_spi_id[] = { diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index b6fd412441a1..9d6431338fb7 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -33,10 +33,8 @@ #define PCM3168A_FMT_DSP_B 0x5 #define PCM3168A_FMT_I2S_TDM 0x6 #define PCM3168A_FMT_LEFT_J_TDM 0x7 -#define PCM3168A_FMT_DSP_MASK 0x4 -#define PCM3168A_NUM_SUPPLIES 6 -static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { +static const char *const pcm3168a_supply_names[] = { "VDD1", "VDD2", "VCCAD1", @@ -50,15 +48,15 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { /* ADC/DAC side parameters */ struct pcm3168a_io_params { - bool master_mode; - unsigned int fmt; + bool provider_mode; + unsigned int format; int tdm_slots; u32 tdm_mask; int slot_width; }; struct pcm3168a_priv { - struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; + struct regulator_bulk_data supplies[ARRAY_SIZE(pcm3168a_supply_names)]; struct regmap *regmap; struct clk *scki; struct gpio_desc *gpio_rst; @@ -329,10 +327,11 @@ static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE; unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6; - if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) { + if (io_params->format == SND_SOC_DAIFMT_RIGHT_J) { /* S16_LE is only supported in RIGHT_J mode */ formats |= SNDRV_PCM_FMTBIT_S16_LE; @@ -340,7 +339,7 @@ static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai) * If multi DIN/DOUT is not selected, RIGHT_J can only support * two channels (no TDM support) */ - if (pcm3168a->io_params[dai->id].tdm_slots != 2) + if (io_params->tdm_slots != 2) channel_max = 2; } @@ -357,39 +356,30 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - u32 fmt, reg, mask, shift; - bool master_mode; + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; + bool provider_mode; switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_LEFT_J: - fmt = PCM3168A_FMT_LEFT_J; - break; case SND_SOC_DAIFMT_I2S: - fmt = PCM3168A_FMT_I2S; - break; case SND_SOC_DAIFMT_RIGHT_J: - fmt = PCM3168A_FMT_RIGHT_J; - break; case SND_SOC_DAIFMT_DSP_A: - fmt = PCM3168A_FMT_DSP_A; - break; case SND_SOC_DAIFMT_DSP_B: - fmt = PCM3168A_FMT_DSP_B; break; default: dev_err(component->dev, "unsupported dai format\n"); return -EINVAL; } - switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - master_mode = false; + switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + provider_mode = false; break; - case SND_SOC_DAIFMT_CBM_CFM: - master_mode = true; + case SND_SOC_DAIFMT_CBP_CFP: + provider_mode = true; break; default: - dev_err(component->dev, "unsupported master/slave mode\n"); + dev_err(component->dev, "unsupported provider mode\n"); return -EINVAL; } @@ -400,20 +390,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) return -EINVAL; } - if (dai->id == PCM3168A_DAI_DAC) { - reg = PCM3168A_DAC_PWR_MST_FMT; - mask = PCM3168A_DAC_FMT_MASK; - shift = PCM3168A_DAC_FMT_SHIFT; - } else { - reg = PCM3168A_ADC_MST_FMT; - mask = PCM3168A_ADC_FMTAD_MASK; - shift = PCM3168A_ADC_FMTAD_SHIFT; - } - - pcm3168a->io_params[dai->id].master_mode = master_mode; - pcm3168a->io_params[dai->id].fmt = fmt; - - regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + io_params->provider_mode = provider_mode; + io_params->format = format & SND_SOC_DAIFMT_FORMAT_MASK; pcm3168a_update_fixup_pcm_stream(dai); @@ -462,41 +440,47 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; - bool master_mode; - u32 val, mask, shift, reg; - unsigned int rate, fmt, ratio, max_ratio; - unsigned int tdm_slots; - int i, slot_width; - - rate = params_rate(params); - - ratio = pcm3168a->sysclk / rate; + bool provider_mode, tdm_mode; + unsigned int format; + unsigned int reg, mask, ms, ms_shift, fmt, fmt_shift, ratio, tdm_slots; + int i, num_scki_ratios, slot_width; if (dai->id == PCM3168A_DAI_DAC) { - max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; + num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_DAC; reg = PCM3168A_DAC_PWR_MST_FMT; - mask = PCM3168A_DAC_MSDA_MASK; - shift = PCM3168A_DAC_MSDA_SHIFT; + mask = PCM3168A_DAC_MSDA_MASK | PCM3168A_DAC_FMT_MASK; + ms_shift = PCM3168A_DAC_MSDA_SHIFT; + fmt_shift = PCM3168A_DAC_FMT_SHIFT; } else { - max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; + num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_ADC; reg = PCM3168A_ADC_MST_FMT; - mask = PCM3168A_ADC_MSAD_MASK; - shift = PCM3168A_ADC_MSAD_SHIFT; + mask = PCM3168A_ADC_MSAD_MASK | PCM3168A_ADC_FMTAD_MASK; + ms_shift = PCM3168A_ADC_MSAD_SHIFT; + fmt_shift = PCM3168A_ADC_FMTAD_SHIFT; } - master_mode = io_params->master_mode; - fmt = io_params->fmt; + provider_mode = io_params->provider_mode; - for (i = 0; i < max_ratio; i++) { - if (pcm3168a_scki_ratios[i] == ratio) - break; - } + if (provider_mode) { + ratio = pcm3168a->sysclk / params_rate(params); - if (i == max_ratio) { - dev_err(component->dev, "unsupported sysclk ratio\n"); - return -EINVAL; + for (i = 0; i < num_scki_ratios; i++) { + if (pcm3168a_scki_ratios[i] == ratio) + break; + } + + if (i == num_scki_ratios) { + dev_err(component->dev, "unsupported sysclk ratio\n"); + return -EINVAL; + } + + ms = (i + 1); + } else { + ms = 0; } + format = io_params->format; + if (io_params->slot_width) slot_width = io_params->slot_width; else @@ -504,15 +488,15 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, switch (slot_width) { case 16: - if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) { - dev_err(component->dev, "16-bit slots are supported only for slave mode using right justified\n"); + if (provider_mode || (format != SND_SOC_DAIFMT_RIGHT_J)) { + dev_err(component->dev, "16-bit slots are supported only for consumer mode using right justified\n"); return -EINVAL; } - fmt = PCM3168A_FMT_RIGHT_J_16; break; case 24: - if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) { - dev_err(component->dev, "24-bit slots not supported in master mode, or slave mode using DSP\n"); + if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || + (format == SND_SOC_DAIFMT_DSP_B)) { + dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); return -EINVAL; } break; @@ -536,15 +520,14 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, * If pcm3168a->tdm_slots is set to 2 then DIN1/2/3/4 and DOUT1/2/3 is * used in normal mode, no need to switch to TDM modes. */ - if (tdm_slots > 2) { - switch (fmt) { - case PCM3168A_FMT_I2S: - case PCM3168A_FMT_DSP_A: - fmt = PCM3168A_FMT_I2S_TDM; - break; - case PCM3168A_FMT_LEFT_J: - case PCM3168A_FMT_DSP_B: - fmt = PCM3168A_FMT_LEFT_J_TDM; + tdm_mode = (tdm_slots > 2); + + if (tdm_mode) { + switch (format) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_B: break; default: dev_err(component->dev, @@ -553,22 +536,29 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, } } - if (master_mode) - val = ((i + 1) << shift); - else - val = 0; - - regmap_update_bits(pcm3168a->regmap, reg, mask, val); - - if (dai->id == PCM3168A_DAI_DAC) { - mask = PCM3168A_DAC_FMT_MASK; - shift = PCM3168A_DAC_FMT_SHIFT; - } else { - mask = PCM3168A_ADC_FMTAD_MASK; - shift = PCM3168A_ADC_FMTAD_SHIFT; + switch (format) { + case SND_SOC_DAIFMT_I2S: + fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + fmt = (slot_width == 16) ? PCM3168A_FMT_RIGHT_J_16 : + PCM3168A_FMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_DSP_B; + break; + default: + return -EINVAL; } - regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + regmap_update_bits(pcm3168a->regmap, reg, mask, + (ms << ms_shift) | (fmt << fmt_shift)); return 0; } @@ -726,7 +716,6 @@ static const struct snd_soc_component_driver pcm3168a_driver = { .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int pcm3168a_probe(struct device *dev, struct regmap *regmap) @@ -751,21 +740,14 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); - if (IS_ERR(pcm3168a->gpio_rst)) { - ret = PTR_ERR(pcm3168a->gpio_rst); - if (ret != -EPROBE_DEFER ) - dev_err(dev, "failed to acquire RST gpio: %d\n", ret); - - return ret; - } + if (IS_ERR(pcm3168a->gpio_rst)) + return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst), + "failed to acquire RST gpio\n"); pcm3168a->scki = devm_clk_get(dev, "scki"); - if (IS_ERR(pcm3168a->scki)) { - ret = PTR_ERR(pcm3168a->scki); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to acquire clock 'scki': %d\n", ret); - return ret; - } + if (IS_ERR(pcm3168a->scki)) + return dev_err_probe(dev, PTR_ERR(pcm3168a->scki), + "failed to acquire clock 'scki'\n"); ret = clk_prepare_enable(pcm3168a->scki); if (ret) { @@ -781,8 +763,7 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to request supplies: %d\n", ret); + dev_err_probe(dev, ret, "failed to request supplies\n"); goto err_clk; } diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index f39f98bbc97f..3401a25341e6 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -28,7 +28,6 @@ static struct snd_soc_component_driver soc_component_dev_pcm5102a = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int pcm5102a_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index 633f7ebe29a3..9dfbbe8f4a0b 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -13,8 +13,7 @@ #include "pcm512x.h" -static int pcm512x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int pcm512x_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config = pcm512x_regmap; @@ -30,10 +29,9 @@ static int pcm512x_i2c_probe(struct i2c_client *i2c, return pcm512x_probe(&i2c->dev, regmap); } -static int pcm512x_i2c_remove(struct i2c_client *i2c) +static void pcm512x_i2c_remove(struct i2c_client *i2c) { pcm512x_remove(&i2c->dev); - return 0; } static const struct i2c_device_id pcm512x_i2c_id[] = { @@ -68,7 +66,7 @@ MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match); #endif static struct i2c_driver pcm512x_i2c_driver = { - .probe = pcm512x_i2c_probe, + .probe_new = pcm512x_i2c_probe, .remove = pcm512x_i2c_remove, .id_table = pcm512x_i2c_id, .driver = { diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 7cf559b47e1c..4d29e7196380 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -26,10 +26,9 @@ static int pcm512x_spi_probe(struct spi_device *spi) return pcm512x_probe(&spi->dev, regmap); } -static int pcm512x_spi_remove(struct spi_device *spi) +static void pcm512x_spi_remove(struct spi_device *spi) { pcm512x_remove(&spi->dev); - return 0; } static const struct spi_device_id pcm512x_spi_id[] = { diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 60dee41816dc..767463e82665 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -652,12 +652,12 @@ static int pcm512x_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + switch (pcm512x->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBP_CFC: return pcm512x_dai_startup_master(substream, dai); - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: return pcm512x_dai_startup_slave(substream, dai); default: @@ -1202,8 +1202,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return ret; } - if ((pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS) { + if ((pcm512x->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_CBC_CFC) { ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, PCM512x_DCAS, 0); if (ret != 0) { @@ -1340,21 +1340,21 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int afmt; int offset = 0; int clock_output; - int master_mode; + int provider_mode; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: clock_output = 0; - master_mode = 0; + provider_mode = 0; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clock_output = PCM512x_BCKO | PCM512x_LRKO; - master_mode = PCM512x_RLRK | PCM512x_RBCK; + provider_mode = PCM512x_RLRK | PCM512x_RBCK; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: clock_output = PCM512x_BCKO; - master_mode = PCM512x_RBCK; + provider_mode = PCM512x_RBCK; break; default: return -EINVAL; @@ -1370,9 +1370,9 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, PCM512x_RLRK | PCM512x_RBCK, - master_mode); + provider_mode); if (ret != 0) { - dev_err(component->dev, "Failed to enable master mode: %d\n", ret); + dev_err(component->dev, "Failed to enable provider mode: %d\n", ret); return ret; } @@ -1512,7 +1512,6 @@ static const struct snd_soc_component_driver pcm512x_component_driver = { .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_range_cfg pcm512x_range = { diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 758d439e8c7a..1d523bfd9d84 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -69,11 +69,11 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) snd_soc_component_get_drvdata(dai->component); unsigned int val; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; break; default: @@ -481,7 +481,7 @@ static int rk3328_platform_probe(struct platform_device *pdev) ret = clk_prepare_enable(rk3328->pclk); if (ret < 0) { dev_err(&pdev->dev, "failed to enable acodec pclk\n"); - return ret; + goto err_unprepare_mclk; } base = devm_platform_ioremap_resource(pdev, 0); diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 03f24edfe4f6..2a5b274bfc0f 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -444,7 +444,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rk817 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, .controls = rk817_volume_controls, .num_controls = ARRAY_SIZE(rk817_volume_controls), .dapm_routes = rk817_dapm_routes, @@ -489,7 +488,7 @@ static int rk817_platform_probe(struct platform_device *pdev) rk817_codec_parse_dt_property(&pdev->dev, rk817_codec_data); - rk817_codec_data->mclk = clk_get(pdev->dev.parent, "mclk"); + rk817_codec_data->mclk = devm_clk_get(pdev->dev.parent, "mclk"); if (IS_ERR(rk817_codec_data->mclk)) { dev_dbg(&pdev->dev, "Unable to get mclk\n"); ret = -ENXIO; @@ -508,12 +507,14 @@ static int rk817_platform_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "%s() register codec error %d\n", __func__, ret); - goto err_; + goto err_clk; } return 0; -err_: +err_clk: + clk_disable_unprepare(rk817_codec_data->mclk); +err_: return ret; } diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index b62301a6281f..c1568216126e 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2176,7 +2176,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1011 = { .set_pll = rt1011_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1011_regmap = { @@ -2433,8 +2432,7 @@ static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) return 0; } -static int rt1011_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1011_i2c_probe(struct i2c_client *i2c) { struct rt1011_priv *rt1011; int ret; @@ -2485,7 +2483,7 @@ static struct i2c_driver rt1011_i2c_driver = { .of_match_table = of_match_ptr(rt1011_of_match), .acpi_match_table = ACPI_PTR(rt1011_acpi_match) }, - .probe = rt1011_i2c_probe, + .probe_new = rt1011_i2c_probe, .shutdown = rt1011_i2c_shutdown, .id_table = rt1011_i2c_id, }; diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 6a27dfacd81c..57d0f1c69e46 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1071,7 +1071,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1015 = { .set_pll = rt1015_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1015_regmap = { @@ -1113,8 +1112,7 @@ static void rt1015_parse_dt(struct rt1015_priv *rt1015, struct device *dev) &rt1015->pdata.power_up_delay_ms); } -static int rt1015_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1015_i2c_probe(struct i2c_client *i2c) { struct rt1015_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt1015_priv *rt1015; @@ -1172,7 +1170,7 @@ static struct i2c_driver rt1015_i2c_driver = { .of_match_table = of_match_ptr(rt1015_of_match), .acpi_match_table = ACPI_PTR(rt1015_acpi_match), }, - .probe = rt1015_i2c_probe, + .probe_new = rt1015_i2c_probe, .shutdown = rt1015_i2c_shutdown, .id_table = rt1015_i2c_id, }; diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 415cfb3b2f0d..06800dad8798 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -89,7 +89,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver rt1015p_dai_driver = { diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 9845cdddcb4c..37eeec650f03 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -595,7 +595,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1016 = { .set_pll = rt1016_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1016_regmap = { @@ -631,8 +630,7 @@ static const struct acpi_device_id rt1016_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1016_acpi_match); #endif -static int rt1016_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1016_i2c_probe(struct i2c_client *i2c) { struct rt1016_priv *rt1016; int ret; @@ -685,7 +683,7 @@ static struct i2c_driver rt1016_i2c_driver = { .of_match_table = of_match_ptr(rt1016_of_match), .acpi_match_table = ACPI_PTR(rt1016_acpi_match), }, - .probe = rt1016_i2c_probe, + .probe_new = rt1016_i2c_probe, .shutdown = rt1016_i2c_shutdown, .id_table = rt1016_i2c_id, }; diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 80b7ca0e4e1e..49f527c61a7a 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -391,18 +391,18 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; - unsigned int val = 0, rx_slotnum; + unsigned int cn = 0, cl = 0, rx_slotnum; int ret = 0, first_bit; switch (slots) { case 4: - val |= RT1019_I2S_TX_4CH; + cn = RT1019_I2S_TX_4CH; break; case 6: - val |= RT1019_I2S_TX_6CH; + cn = RT1019_I2S_TX_6CH; break; case 8: - val |= RT1019_I2S_TX_8CH; + cn = RT1019_I2S_TX_8CH; break; case 2: break; @@ -412,16 +412,16 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, switch (slot_width) { case 20: - val |= RT1019_I2S_DL_20; + cl = RT1019_TDM_CL_20; break; case 24: - val |= RT1019_I2S_DL_24; + cl = RT1019_TDM_CL_24; break; case 32: - val |= RT1019_I2S_DL_32; + cl = RT1019_TDM_CL_32; break; case 8: - val |= RT1019_I2S_DL_8; + cl = RT1019_TDM_CL_8; break; case 16: break; @@ -470,8 +470,10 @@ static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, goto _set_tdm_err_; } + snd_soc_component_update_bits(component, RT1019_TDM_1, + RT1019_TDM_CL_MASK, cl); snd_soc_component_update_bits(component, RT1019_TDM_2, - RT1019_I2S_CH_TX_MASK | RT1019_I2S_DF_MASK, val); + RT1019_I2S_CH_TX_MASK, cn); _set_tdm_err_: return ret; @@ -515,14 +517,14 @@ static struct snd_soc_dai_driver rt1019_dai[] = { }; static const struct snd_soc_component_driver soc_component_dev_rt1019 = { - .probe = rt1019_probe, + .probe = rt1019_probe, .controls = rt1019_snd_controls, .num_controls = ARRAY_SIZE(rt1019_snd_controls), .dapm_widgets = rt1019_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets), .dapm_routes = rt1019_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes), - .non_legacy_dai_naming = 1, + .endianness = 1, }; static const struct regmap_config rt1019_regmap = { @@ -558,8 +560,7 @@ static const struct acpi_device_id rt1019_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match); #endif -static int rt1019_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1019_i2c_probe(struct i2c_client *i2c) { struct rt1019_priv *rt1019; int ret; @@ -599,7 +600,7 @@ static struct i2c_driver rt1019_i2c_driver = { .of_match_table = of_match_ptr(rt1019_of_match), .acpi_match_table = ACPI_PTR(rt1019_acpi_match), }, - .probe = rt1019_i2c_probe, + .probe_new = rt1019_i2c_probe, .id_table = rt1019_i2c_id, }; module_i2c_driver(rt1019_i2c_driver); diff --git a/sound/soc/codecs/rt1019.h b/sound/soc/codecs/rt1019.h index 64df831eeb72..48ba15efb48d 100644 --- a/sound/soc/codecs/rt1019.h +++ b/sound/soc/codecs/rt1019.h @@ -95,6 +95,12 @@ #define RT1019_TDM_BCLK_MASK (0x1 << 6) #define RT1019_TDM_BCLK_NORM (0x0 << 6) #define RT1019_TDM_BCLK_INV (0x1 << 6) +#define RT1019_TDM_CL_MASK (0x7) +#define RT1019_TDM_CL_8 (0x4) +#define RT1019_TDM_CL_32 (0x3) +#define RT1019_TDM_CL_24 (0x2) +#define RT1019_TDM_CL_20 (0x1) +#define RT1019_TDM_CL_16 (0x0) /* 0x0401 TDM Control-2 */ #define RT1019_I2S_CH_TX_MASK (0x3 << 6) diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index a9c473537a91..5b39a440b6dc 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -946,7 +946,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1305 = { .set_pll = rt1305_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1305_regmap = { @@ -1117,8 +1116,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305) regcache_cache_bypass(rt1305->regmap, false); } -static int rt1305_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1305_i2c_probe(struct i2c_client *i2c) { struct rt1305_priv *rt1305; int ret; @@ -1172,7 +1170,7 @@ static struct i2c_driver rt1305_i2c_driver = { .acpi_match_table = ACPI_PTR(rt1305_acpi_match) #endif }, - .probe = rt1305_i2c_probe, + .probe_new = rt1305_i2c_probe, .shutdown = rt1305_i2c_shutdown, .id_table = rt1305_i2c_id, }; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f716668de640..f99aed353f10 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -50,6 +50,9 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg) case 0x3008: case 0x300a: case 0xc000: + case 0xc710: + case 0xc860 ... 0xc863: + case 0xc870 ... 0xc873: return true; default: return false; @@ -159,12 +162,46 @@ static int rt1308_read_prop(struct sdw_slave *slave) return 0; } +static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308) +{ + unsigned int efuse_m_btl_l, efuse_m_btl_r, tmp; + unsigned int efuse_c_btl_l, efuse_c_btl_r; + + /* read efuse to apply calibration parameters */ + regmap_write(rt1308->regmap, 0xc7f0, 0x04); + regmap_write(rt1308->regmap, 0xc7f1, 0xfe); + msleep(100); + regmap_write(rt1308->regmap, 0xc7f0, 0x44); + msleep(20); + regmap_write(rt1308->regmap, 0xc240, 0x10); + + regmap_read(rt1308->regmap, 0xc861, &tmp); + efuse_m_btl_l = tmp; + regmap_read(rt1308->regmap, 0xc860, &tmp); + efuse_m_btl_l = efuse_m_btl_l | (tmp << 8); + regmap_read(rt1308->regmap, 0xc863, &tmp); + efuse_c_btl_l = tmp; + regmap_read(rt1308->regmap, 0xc862, &tmp); + efuse_c_btl_l = efuse_c_btl_l | (tmp << 8); + regmap_read(rt1308->regmap, 0xc871, &tmp); + efuse_m_btl_r = tmp; + regmap_read(rt1308->regmap, 0xc870, &tmp); + efuse_m_btl_r = efuse_m_btl_r | (tmp << 8); + regmap_read(rt1308->regmap, 0xc873, &tmp); + efuse_c_btl_r = tmp; + regmap_read(rt1308->regmap, 0xc872, &tmp); + efuse_c_btl_r = efuse_c_btl_r | (tmp << 8); + dev_dbg(&rt1308->sdw_slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__, + efuse_m_btl_l, efuse_m_btl_r); + dev_dbg(&rt1308->sdw_slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__, + efuse_c_btl_l, efuse_c_btl_r); +} + static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); int ret = 0; - unsigned int efuse_m_btl_l, efuse_m_btl_r, tmp; - unsigned int efuse_c_btl_l, efuse_c_btl_r; + unsigned int tmp; if (rt1308->hw_init) return 0; @@ -196,36 +233,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) /* sw reset */ regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); - /* read efuse */ - regmap_write(rt1308->regmap, 0xc360, 0x01); - regmap_write(rt1308->regmap, 0xc361, 0x80); - regmap_write(rt1308->regmap, 0xc7f0, 0x04); - regmap_write(rt1308->regmap, 0xc7f1, 0xfe); - msleep(100); - regmap_write(rt1308->regmap, 0xc7f0, 0x44); - msleep(20); - regmap_write(rt1308->regmap, 0xc240, 0x10); - - regmap_read(rt1308->regmap, 0xc861, &tmp); - efuse_m_btl_l = tmp; - regmap_read(rt1308->regmap, 0xc860, &tmp); - efuse_m_btl_l = efuse_m_btl_l | (tmp << 8); - regmap_read(rt1308->regmap, 0xc863, &tmp); - efuse_c_btl_l = tmp; - regmap_read(rt1308->regmap, 0xc862, &tmp); - efuse_c_btl_l = efuse_c_btl_l | (tmp << 8); - regmap_read(rt1308->regmap, 0xc871, &tmp); - efuse_m_btl_r = tmp; - regmap_read(rt1308->regmap, 0xc870, &tmp); - efuse_m_btl_r = efuse_m_btl_r | (tmp << 8); - regmap_read(rt1308->regmap, 0xc873, &tmp); - efuse_c_btl_r = tmp; - regmap_read(rt1308->regmap, 0xc872, &tmp); - efuse_c_btl_r = efuse_c_btl_r | (tmp << 8); - dev_dbg(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__, - efuse_m_btl_l, efuse_m_btl_r); - dev_dbg(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__, - efuse_c_btl_l, efuse_c_btl_r); + regmap_read(rt1308->regmap, 0xc710, &tmp); + rt1308->hw_ver = tmp; + dev_dbg(dev, "%s, hw_ver=0x%x\n", __func__, rt1308->hw_ver); /* initial settings */ regmap_write(rt1308->regmap, 0xc103, 0xc0); @@ -242,8 +252,14 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc062, 0x05); regmap_write(rt1308->regmap, 0xc171, 0x07); regmap_write(rt1308->regmap, 0xc173, 0x0d); - regmap_write(rt1308->regmap, 0xc311, 0x7f); - regmap_write(rt1308->regmap, 0xc900, 0x90); + if (rt1308->hw_ver == RT1308_VER_C) { + regmap_write(rt1308->regmap, 0xc311, 0x7f); + regmap_write(rt1308->regmap, 0xc300, 0x09); + } else { + regmap_write(rt1308->regmap, 0xc311, 0x4f); + regmap_write(rt1308->regmap, 0xc300, 0x0b); + } + regmap_write(rt1308->regmap, 0xc900, 0x5a); regmap_write(rt1308->regmap, 0xc1a0, 0x84); regmap_write(rt1308->regmap, 0xc1a1, 0x01); regmap_write(rt1308->regmap, 0xc360, 0x78); @@ -253,7 +269,6 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc070, 0x00); regmap_write(rt1308->regmap, 0xc100, 0xd7); regmap_write(rt1308->regmap, 0xc101, 0xd7); - regmap_write(rt1308->regmap, 0xc300, 0x09); if (rt1308->first_hw_init) { regcache_cache_bypass(rt1308->regmap, false); @@ -323,6 +338,8 @@ static int rt1308_classd_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1308_sdw_priv *rt1308 = + snd_soc_component_get_drvdata(component); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -331,6 +348,7 @@ static int rt1308_classd_event(struct snd_soc_dapm_widget *w, RT1308_SDW_OFFSET | (RT1308_POWER_STATUS << 4), 0x3, 0x3); msleep(40); + rt1308_apply_calib_params(rt1308); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_component_update_bits(component, @@ -601,19 +619,32 @@ static const struct sdw_slave_ops rt1308_slave_ops = { .bus_config = rt1308_bus_config, }; +static int rt1308_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { + .probe = rt1308_sdw_component_probe, .controls = rt1308_snd_controls, .num_controls = ARRAY_SIZE(rt1308_snd_controls), .dapm_widgets = rt1308_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1308_dapm_widgets), .dapm_routes = rt1308_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1308_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops rt1308_aif_dai_ops = { .hw_params = rt1308_sdw_hw_params, .hw_free = rt1308_sdw_pcm_hw_free, - .set_sdw_stream = rt1308_set_sdw_stream, + .set_stream = rt1308_set_sdw_stream, .shutdown = rt1308_sdw_shutdown, .set_tdm_slot = rt1308_sdw_set_tdm_slot, }; @@ -683,6 +714,16 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, return 0; } +static int rt1308_sdw_remove(struct sdw_slave *slave) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); + + if (rt1308->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt1308_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0), {}, @@ -719,6 +760,8 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev) msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } @@ -742,6 +785,7 @@ static struct sdw_driver rt1308_sdw_driver = { .pm = &rt1308_pm, }, .probe = rt1308_sdw_probe, + .remove = rt1308_sdw_remove, .ops = &rt1308_slave_ops, .id_table = rt1308_id, }; diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h index c5ce75666dcc..62ce27799307 100644 --- a/sound/soc/codecs/rt1308-sdw.h +++ b/sound/soc/codecs/rt1308-sdw.h @@ -139,9 +139,12 @@ static const struct reg_default rt1308_reg_defaults[] = { { 0x3005, 0x23 }, { 0x3008, 0x02 }, { 0x300a, 0x00 }, + { 0xc000 | (RT1308_DATA_PATH << 4), 0x00 }, { 0xc003 | (RT1308_DAC_SET << 4), 0x00 }, + { 0xc000 | (RT1308_POWER << 4), 0x00 }, { 0xc001 | (RT1308_POWER << 4), 0x00 }, { 0xc002 | (RT1308_POWER << 4), 0x00 }, + { 0xc000 | (RT1308_POWER_STATUS << 4), 0x00 }, }; #define RT1308_SDW_OFFSET 0xc000 @@ -162,6 +165,7 @@ struct rt1308_sdw_priv { bool first_hw_init; int rx_mask; int slots; + int hw_ver; }; struct sdw_stream_data { diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index c555b77b3c5c..d2a8e9fe3e23 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -765,7 +765,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1308 = { .set_pll = rt1308_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1308_regmap = { @@ -814,8 +813,7 @@ static void rt1308_efuse(struct rt1308_priv *rt1308) regmap_write(rt1308->regmap, RT1308_PVDD_OFFSET_CTL, 0x10000000); } -static int rt1308_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt1308_i2c_probe(struct i2c_client *i2c) { struct rt1308_priv *rt1308; int ret; @@ -864,7 +862,7 @@ static struct i2c_driver rt1308_i2c_driver = { .of_match_table = of_match_ptr(rt1308_of_match), .acpi_match_table = ACPI_PTR(rt1308_acpi_match), }, - .probe = rt1308_i2c_probe, + .probe_new = rt1308_i2c_probe, .shutdown = rt1308_i2c_shutdown, .id_table = rt1308_i2c_id, }; diff --git a/sound/soc/codecs/rt1308.h b/sound/soc/codecs/rt1308.h index ff7c423e879e..d3a0f91630ca 100644 --- a/sound/soc/codecs/rt1308.h +++ b/sound/soc/codecs/rt1308.h @@ -286,4 +286,9 @@ enum { RT1308_AIFS }; +enum rt1308_hw_ver { + RT1308_VER_C = 2, + RT1308_VER_D +}; + #endif /* end of _RT1308_H_ */ diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 09b4914bba1b..ed0a11436362 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -590,19 +590,32 @@ static struct sdw_slave_ops rt1316_slave_ops = { .update_status = rt1316_update_status, }; +static int rt1316_sdw_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_component_sdw_rt1316 = { + .probe = rt1316_sdw_component_probe, .controls = rt1316_snd_controls, .num_controls = ARRAY_SIZE(rt1316_snd_controls), .dapm_widgets = rt1316_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1316_dapm_widgets), .dapm_routes = rt1316_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1316_dapm_routes), + .endianness = 1, }; static const struct snd_soc_dai_ops rt1316_aif_dai_ops = { .hw_params = rt1316_sdw_hw_params, .hw_free = rt1316_sdw_pcm_hw_free, - .set_sdw_stream = rt1316_set_sdw_stream, + .set_stream = rt1316_set_sdw_stream, .shutdown = rt1316_sdw_shutdown, }; @@ -675,6 +688,16 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, return rt1316_sdw_init(&slave->dev, regmap, slave); } +static int rt1316_sdw_remove(struct sdw_slave *slave) +{ + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); + + if (rt1316->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt1316_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0), {}, @@ -711,6 +734,8 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev) msecs_to_jiffies(RT1316_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } @@ -734,6 +759,7 @@ static struct sdw_driver rt1316_sdw_driver = { .pm = &rt1316_pm, }, .probe = rt1316_sdw_probe, + .remove = rt1316_sdw_remove, .ops = &rt1316_slave_ops, .id_table = rt1316_id, }; diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 0d3773c576f8..4667bf7561b1 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -980,14 +980,11 @@ static int rt274_probe(struct snd_soc_component *component) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); rt274->component = component; + INIT_DELAYED_WORK(&rt274->jack_detect_work, rt274_jack_detect_work); - if (rt274->i2c->irq) { - INIT_DELAYED_WORK(&rt274->jack_detect_work, - rt274_jack_detect_work); + if (rt274->i2c->irq) schedule_delayed_work(&rt274->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } @@ -996,6 +993,7 @@ static void rt274_remove(struct snd_soc_component *component) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt274->jack_detect_work); + rt274->component = NULL; } #ifdef CONFIG_PM @@ -1075,7 +1073,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt274 = { .num_dapm_routes = ARRAY_SIZE(rt274_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt274_regmap = { @@ -1114,8 +1111,7 @@ static const struct acpi_device_id rt274_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt274_acpi_match); #endif -static int rt274_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt274_i2c_probe(struct i2c_client *i2c) { struct rt274_priv *rt274; @@ -1208,14 +1204,12 @@ static int rt274_i2c_probe(struct i2c_client *i2c, return ret; } -static int rt274_i2c_remove(struct i2c_client *i2c) +static void rt274_i2c_remove(struct i2c_client *i2c) { struct rt274_priv *rt274 = i2c_get_clientdata(i2c); if (i2c->irq) free_irq(i2c->irq, rt274); - - return 0; } @@ -1227,7 +1221,7 @@ static struct i2c_driver rt274_i2c_driver = { .of_match_table = of_match_ptr(rt274_of_match), #endif }, - .probe = rt274_i2c_probe, + .probe_new = rt274_i2c_probe, .remove = rt274_i2c_remove, .id_table = rt274_i2c_id, }; diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index caa720884e3e..ceb56647e369 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -311,7 +311,8 @@ static void rt286_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt286_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); @@ -335,7 +336,6 @@ int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j return 0; } -EXPORT_SYMBOL_GPL(rt286_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) @@ -947,17 +947,11 @@ static int rt286_probe(struct snd_soc_component *component) struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); rt286->component = component; + INIT_DELAYED_WORK(&rt286->jack_detect_work, rt286_jack_detect_work); - if (rt286->i2c->irq) { - regmap_update_bits(rt286->regmap, - RT286_IRQ_CTRL, 0x2, 0x2); - - INIT_DELAYED_WORK(&rt286->jack_detect_work, - rt286_jack_detect_work); + if (rt286->i2c->irq) schedule_delayed_work(&rt286->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(50)); return 0; } @@ -966,6 +960,7 @@ static void rt286_remove(struct snd_soc_component *component) struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt286->jack_detect_work); + rt286->component = NULL; } #ifdef CONFIG_PM @@ -1055,6 +1050,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = { .suspend = rt286_suspend, .resume = rt286_resume, .set_bias_level = rt286_set_bias_level, + .set_jack = rt286_mic_detect, .controls = rt286_snd_controls, .num_controls = ARRAY_SIZE(rt286_snd_controls), .dapm_widgets = rt286_dapm_widgets, @@ -1063,7 +1059,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = { .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt286_regmap = { @@ -1134,8 +1129,7 @@ static const struct dmi_system_id dmi_dell[] = { { } }; -static int rt286_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt286_i2c_probe(struct i2c_client *i2c) { struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt286_priv *rt286; @@ -1255,14 +1249,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c, return ret; } -static int rt286_i2c_remove(struct i2c_client *i2c) +static void rt286_i2c_remove(struct i2c_client *i2c) { struct rt286_priv *rt286 = i2c_get_clientdata(i2c); if (i2c->irq) free_irq(i2c->irq, rt286); - - return 0; } @@ -1271,7 +1263,7 @@ static struct i2c_driver rt286_i2c_driver = { .name = "rt286", .acpi_match_table = ACPI_PTR(rt286_acpi_match), }, - .probe = rt286_i2c_probe, + .probe_new = rt286_i2c_probe, .remove = rt286_i2c_remove, .id_table = rt286_i2c_id, }; diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h index f27a4e71d5b6..4b7a3bd6043d 100644 --- a/sound/soc/codecs/rt286.h +++ b/sound/soc/codecs/rt286.h @@ -196,7 +196,5 @@ enum { RT286_AIFS, }; -int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT286_H__ */ diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index c592c40a7ab3..a2ce52dafea8 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -326,39 +326,37 @@ static void rt298_jack_detect_work(struct work_struct *work) SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); } -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) +static int rt298_mic_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm; - bool hp = false; - bool mic = false; - int status = 0; - /* If jack in NULL, disable HS jack */ - if (!jack) { + rt298->jack = jack; + + if (jack) { + /* Enable IRQ */ + if (rt298->jack->status & SND_JACK_HEADPHONE) + snd_soc_dapm_force_enable_pin(dapm, "LDO1"); + if (rt298->jack->status & SND_JACK_MICROPHONE) { + snd_soc_dapm_force_enable_pin(dapm, "HV"); + snd_soc_dapm_force_enable_pin(dapm, "VREF"); + } + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + /* Send an initial empty report */ + snd_soc_jack_report(rt298->jack, rt298->jack->status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + } else { + /* Disable IRQ */ regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0); - dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_disable_pin(dapm, "HV"); + snd_soc_dapm_disable_pin(dapm, "VREF"); snd_soc_dapm_disable_pin(dapm, "LDO1"); - snd_soc_dapm_sync(dapm); - return 0; } - - rt298->jack = jack; - regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); - - rt298_jack_detect(rt298, &hp, &mic); - if (hp) - status |= SND_JACK_HEADPHONE; - - if (mic) - status |= SND_JACK_MICROPHONE; - - snd_soc_jack_report(rt298->jack, status, - SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + snd_soc_dapm_sync(dapm); return 0; } -EXPORT_SYMBOL_GPL(rt298_mic_detect); static int is_mclk_mode(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) @@ -1011,17 +1009,11 @@ static int rt298_probe(struct snd_soc_component *component) struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); rt298->component = component; + INIT_DELAYED_WORK(&rt298->jack_detect_work, rt298_jack_detect_work); - if (rt298->i2c->irq) { - regmap_update_bits(rt298->regmap, - RT298_IRQ_CTRL, 0x2, 0x2); - - INIT_DELAYED_WORK(&rt298->jack_detect_work, - rt298_jack_detect_work); + if (rt298->i2c->irq) schedule_delayed_work(&rt298->jack_detect_work, - msecs_to_jiffies(1250)); - } - + msecs_to_jiffies(1250)); return 0; } @@ -1030,6 +1022,7 @@ static void rt298_remove(struct snd_soc_component *component) struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt298->jack_detect_work); + rt298->component = NULL; } #ifdef CONFIG_PM @@ -1120,6 +1113,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = { .suspend = rt298_suspend, .resume = rt298_resume, .set_bias_level = rt298_set_bias_level, + .set_jack = rt298_mic_detect, .controls = rt298_snd_controls, .num_controls = ARRAY_SIZE(rt298_snd_controls), .dapm_widgets = rt298_dapm_widgets, @@ -1128,7 +1122,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = { .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt298_regmap = { @@ -1176,8 +1169,7 @@ static const struct dmi_system_id force_combo_jack_table[] = { { } }; -static int rt298_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt298_i2c_probe(struct i2c_client *i2c) { struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt298_priv *rt298; @@ -1298,14 +1290,12 @@ static int rt298_i2c_probe(struct i2c_client *i2c, return ret; } -static int rt298_i2c_remove(struct i2c_client *i2c) +static void rt298_i2c_remove(struct i2c_client *i2c) { struct rt298_priv *rt298 = i2c_get_clientdata(i2c); if (i2c->irq) free_irq(i2c->irq, rt298); - - return 0; } @@ -1314,7 +1304,7 @@ static struct i2c_driver rt298_i2c_driver = { .name = "rt298", .acpi_match_table = ACPI_PTR(rt298_acpi_match), }, - .probe = rt298_i2c_probe, + .probe_new = rt298_i2c_probe, .remove = rt298_i2c_remove, .id_table = rt298_i2c_id, }; diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index ed2b8fd87f4c..f1be9c135401 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h @@ -207,7 +207,5 @@ enum { RT298_AIFS, }; -int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); - #endif /* __RT298_H__ */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 577680df7052..b9bcf04d4dc9 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -419,7 +419,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, } } - return 0; + return 1; } static const struct snd_kcontrol_new rt5514_snd_controls[] = { @@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5514 = { .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5514_i2c_regmap = { @@ -1252,8 +1251,7 @@ static __maybe_unused int rt5514_i2c_resume(struct device *dev) return 0; } -static int rt5514_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5514_i2c_probe(struct i2c_client *i2c) { struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5514_priv *rt5514; @@ -1330,7 +1328,7 @@ static struct i2c_driver rt5514_i2c_driver = { .of_match_table = of_match_ptr(rt5514_of_match), .pm = &rt5514_i2_pm_ops, }, - .probe = rt5514_i2c_probe, + .probe_new = rt5514_i2c_probe, .id_table = rt5514_i2c_id, }; module_i2c_driver(rt5514_i2c_driver); diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 8e6414468a87..948abde10463 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1304,7 +1304,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5616 = { .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5616_regmap = { @@ -1337,8 +1336,7 @@ static const struct of_device_id rt5616_of_match[] = { MODULE_DEVICE_TABLE(of, rt5616_of_match); #endif -static int rt5616_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5616_i2c_probe(struct i2c_client *i2c) { struct rt5616_priv *rt5616; unsigned int val; @@ -1390,10 +1388,8 @@ static int rt5616_i2c_probe(struct i2c_client *i2c, rt5616_dai, ARRAY_SIZE(rt5616_dai)); } -static int rt5616_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} +static void rt5616_i2c_remove(struct i2c_client *i2c) +{} static void rt5616_i2c_shutdown(struct i2c_client *client) { @@ -1408,7 +1404,7 @@ static struct i2c_driver rt5616_i2c_driver = { .name = "rt5616", .of_match_table = of_match_ptr(rt5616_of_match), }, - .probe = rt5616_i2c_probe, + .probe_new = rt5616_i2c_probe, .remove = rt5616_i2c_remove, .shutdown = rt5616_i2c_shutdown, .id_table = rt5616_i2c_id, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 38356ea2bd6e..55c232413e2b 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1666,7 +1666,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5631 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id rt5631_i2c_id[] = { @@ -1699,8 +1698,7 @@ static const struct regmap_config rt5631_regmap_config = { .use_single_write = true, }; -static int rt5631_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5631_i2c_probe(struct i2c_client *i2c) { struct rt5631_priv *rt5631; int ret; @@ -1722,17 +1720,15 @@ static int rt5631_i2c_probe(struct i2c_client *i2c, return ret; } -static int rt5631_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void rt5631_i2c_remove(struct i2c_client *client) +{} static struct i2c_driver rt5631_i2c_driver = { .driver = { .name = "rt5631", .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, - .probe = rt5631_i2c_probe, + .probe_new = rt5631_i2c_probe, .remove = rt5631_i2c_remove, .id_table = rt5631_i2c_id, }; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index d01fe73ab9c8..0f8e6dd214b0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -195,6 +195,7 @@ static bool rt5640_volatile_register(struct device *dev, unsigned int reg) case RT5640_PRIV_DATA: case RT5640_PGM_REG_ARR1: case RT5640_PGM_REG_ARR3: + case RT5640_DUMMY2: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: case RT5640_VENDOR_ID2: @@ -1838,9 +1839,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, unsigned int reg_val = 0; unsigned int pll_bit = 0; - if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src) - return 0; - switch (clk_id) { case RT5640_SCLK_S_MCLK: reg_val |= RT5640_SCLK_SRC_MCLK; @@ -1972,7 +1970,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); snd_soc_component_update_bits(component, RT5640_DUMMY1, - 0x0301, 0x0301); + 0x1, 0x1); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); } @@ -1986,7 +1984,12 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000); snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000); snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000); - snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000); + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) + snd_soc_component_write(component, RT5640_PWR_ANLG1, + 0x2818); + else + snd_soc_component_write(component, RT5640_PWR_ANLG1, + 0x0000); snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000); break; @@ -2096,12 +2099,14 @@ EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src); void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); snd_soc_dapm_mutex_lock(dapm); snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); /* OVCD is unreliable when used with RCCLK as sysclk-source */ - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); + if (rt5640->use_platform_clock) + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock"); snd_soc_dapm_sync_unlocked(dapm); snd_soc_dapm_mutex_unlock(dapm); } @@ -2110,9 +2115,11 @@ EXPORT_SYMBOL_GPL(rt5640_enable_micbias1_for_ovcd); void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); + if (rt5640->use_platform_clock) + snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock"); snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); snd_soc_dapm_sync_unlocked(dapm); @@ -2159,7 +2166,11 @@ static bool rt5640_jack_inserted(struct snd_soc_component *component) struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); int val; - val = snd_soc_component_read(component, RT5640_INT_IRQ_ST); + if (rt5640->jd_gpio) + val = gpiod_get_value(rt5640->jd_gpio) ? RT5640_JD_STATUS : 0; + else + val = snd_soc_component_read(component, RT5640_INT_IRQ_ST); + dev_dbg(component->dev, "irq status %#04x\n", val); if (rt5640->jd_inverted) @@ -2297,10 +2308,42 @@ EXPORT_SYMBOL_GPL(rt5640_detect_headset); static void rt5640_jack_work(struct work_struct *work) { struct rt5640_priv *rt5640 = - container_of(work, struct rt5640_priv, jack_work); + container_of(work, struct rt5640_priv, jack_work.work); struct snd_soc_component *component = rt5640->component; int status; + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { + int val, jack_type = 0, hda_mic_plugged, hda_hp_plugged; + + /* mic jack */ + val = snd_soc_component_read(component, RT5640_INT_IRQ_ST); + hda_mic_plugged = !(val & RT5640_JD_STATUS); + dev_dbg(component->dev, "mic jack status %d\n", + hda_mic_plugged); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL1, + RT5640_JD_P_MASK, !hda_mic_plugged << RT5640_JD_P_SFT); + + if (hda_mic_plugged) + jack_type |= SND_JACK_MICROPHONE; + + /* headphone jack */ + val = snd_soc_component_read(component, RT5640_DUMMY2); + hda_hp_plugged = !(val & (0x1 << 11)); + dev_dbg(component->dev, "headphone jack status %d\n", + hda_hp_plugged); + + snd_soc_component_update_bits(component, RT5640_DUMMY2, + (0x1 << 10), !hda_hp_plugged << 10); + + if (hda_hp_plugged) + jack_type |= SND_JACK_HEADPHONE; + + snd_soc_jack_report(rt5640->jack, jack_type, SND_JACK_HEADSET); + + return; + } + if (!rt5640_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ if (rt5640->jack->status & SND_JACK_HEADPHONE) { @@ -2348,16 +2391,32 @@ static void rt5640_jack_work(struct work_struct *work) * disabled the OVCD IRQ, the IRQ pin will stay high and as * we react to edges, we miss the unplug event -> recheck. */ - queue_work(system_long_wq, &rt5640->jack_work); + queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); } } static irqreturn_t rt5640_irq(int irq, void *data) { struct rt5640_priv *rt5640 = data; + int delay = 0; + + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { + cancel_delayed_work_sync(&rt5640->jack_work); + delay = 100; + } if (rt5640->jack) - queue_work(system_long_wq, &rt5640->jack_work); + queue_delayed_work(system_long_wq, &rt5640->jack_work, delay); + + return IRQ_HANDLED; +} + +static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data) +{ + struct rt5640_priv *rt5640 = data; + + queue_delayed_work(system_long_wq, &rt5640->jack_work, + msecs_to_jiffies(JACK_SETTLE_TIME)); return IRQ_HANDLED; } @@ -2366,7 +2425,7 @@ static void rt5640_cancel_work(void *data) { struct rt5640_priv *rt5640 = data; - cancel_work_sync(&rt5640->jack_work); + cancel_delayed_work_sync(&rt5640->jack_work); cancel_delayed_work_sync(&rt5640->bp_work); } @@ -2406,7 +2465,12 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) if (!rt5640->jack) return; - free_irq(rt5640->irq, rt5640); + if (rt5640->jd_gpio_irq_requested) + free_irq(rt5640->jd_gpio_irq, rt5640); + + if (rt5640->irq_requested) + free_irq(rt5640->irq, rt5640); + rt5640_cancel_work(rt5640); if (rt5640->jack->status & SND_JACK_MICROPHONE) { @@ -2415,18 +2479,22 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component) snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); } + rt5640->jd_gpio_irq_requested = false; + rt5640->irq_requested = false; + rt5640->jd_gpio = NULL; rt5640->jack = NULL; } static void rt5640_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *jack) + struct snd_soc_jack *jack, + struct rt5640_set_jack_data *jack_data) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); int ret; /* Select JD-source */ snd_soc_component_update_bits(component, RT5640_JD_CTRL, - RT5640_JD_MASK, rt5640->jd_src); + RT5640_JD_MASK, rt5640->jd_src << RT5640_JD_SFT); /* Selecting GPIO01 as an interrupt */ snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, @@ -2436,12 +2504,8 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - /* Enabling jd2 in general control 1 */ snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41); - /* Enabling jd2 in general control 2 */ - snd_soc_component_write(component, RT5640_DUMMY2, 0x4001); - rt5640_set_ovcd_params(component); /* @@ -2450,12 +2514,25 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, * pin 0/1 instead of it being stuck to 1. So we invert the JD polarity * on systems where the hardware does not already do this. */ - if (rt5640->jd_inverted) - snd_soc_component_write(component, RT5640_IRQ_CTRL1, - RT5640_IRQ_JD_NOR); - else - snd_soc_component_write(component, RT5640_IRQ_CTRL1, - RT5640_IRQ_JD_NOR | RT5640_JD_P_INV); + if (rt5640->jd_inverted) { + if (rt5640->jd_src == RT5640_JD_SRC_JD1_IN4P) + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR); + else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) + snd_soc_component_update_bits(component, RT5640_DUMMY2, + RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK, + RT5640_IRQ_JD2_NOR | RT5640_JD2_EN); + } else { + if (rt5640->jd_src == RT5640_JD_SRC_JD1_IN4P) + snd_soc_component_write(component, RT5640_IRQ_CTRL1, + RT5640_IRQ_JD_NOR | RT5640_JD_P_INV); + else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) + snd_soc_component_update_bits(component, RT5640_DUMMY2, + RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK | + RT5640_JD2_MASK, + RT5640_IRQ_JD2_NOR | RT5640_JD2_P_INV | + RT5640_JD2_EN); + } rt5640->jack = jack; if (rt5640->jack->status & SND_JACK_MICROPHONE) { @@ -2463,28 +2540,111 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, rt5640_enable_micbias1_ovcd_irq(component); } + if (jack_data && jack_data->codec_irq_override) + rt5640->irq = jack_data->codec_irq_override; + + if (jack_data && jack_data->jd_gpio) { + rt5640->jd_gpio = jack_data->jd_gpio; + rt5640->jd_gpio_irq = gpiod_to_irq(rt5640->jd_gpio); + + ret = request_irq(rt5640->jd_gpio_irq, rt5640_jd_gpio_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "rt5640-jd-gpio", rt5640); + if (ret) { + dev_warn(component->dev, "Failed to request jd GPIO IRQ %d: %d\n", + rt5640->jd_gpio_irq, ret); + rt5640_disable_jack_detect(component); + return; + } + rt5640->jd_gpio_irq_requested = true; + } + + if (jack_data && jack_data->use_platform_clock) + rt5640->use_platform_clock = jack_data->use_platform_clock; + ret = request_irq(rt5640->irq, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); - rt5640->irq = -ENXIO; - /* Undo above settings */ rt5640_disable_jack_detect(component); return; } + rt5640->irq_requested = true; /* sync initial jack state */ - queue_work(system_long_wq, &rt5640->jack_work); + queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); +} + +static const struct snd_soc_dapm_route rt5640_hda_jack_dapm_routes[] = { + {"IN1P", NULL, "MICBIAS1"}, + {"IN2P", NULL, "MICBIAS1"}, + {"IN3P", NULL, "MICBIAS1"}, +}; + +static void rt5640_enable_hda_jack_detect( + struct snd_soc_component *component, struct snd_soc_jack *jack) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + int ret; + + /* Select JD1 for Mic */ + snd_soc_component_update_bits(component, RT5640_JD_CTRL, + RT5640_JD_MASK, RT5640_JD_JD1_IN4P); + snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); + + /* Select JD2 for Headphone */ + snd_soc_component_update_bits(component, RT5640_DUMMY2, 0x1100, 0x1100); + + /* Selecting GPIO01 as an interrupt */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, + RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ); + + /* Set GPIO1 output */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, + RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); + + snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0); + + snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, + RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG, + RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG); + usleep_range(10000, 15000); + snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, + RT5640_PWR_FV2, RT5640_PWR_FV2); + + rt5640->jack = jack; + + ret = request_irq(rt5640->irq, rt5640_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); + if (ret) { + dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + rt5640->irq = -ENXIO; + return; + } + + /* sync initial jack state */ + queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); + + snd_soc_dapm_add_routes(dapm, rt5640_hda_jack_dapm_routes, + ARRAY_SIZE(rt5640_hda_jack_dapm_routes)); } static int rt5640_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { - if (jack) - rt5640_enable_jack_detect(component, jack); - else + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + if (jack) { + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) + rt5640_enable_hda_jack_detect(component, jack); + else + rt5640_enable_jack_detect(component, jack, data); + } else { rt5640_disable_jack_detect(component); + } return 0; } @@ -2574,8 +2734,8 @@ static int rt5640_probe(struct snd_soc_component *component) if (device_property_read_u32(component->dev, "realtek,jack-detect-source", &val) == 0) { - if (val <= RT5640_JD_SRC_GPIO4) - rt5640->jd_src = val << RT5640_JD_SFT; + if (val <= RT5640_JD_SRC_HDA_HEADER) + rt5640->jd_src = val; else dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", val); @@ -2632,6 +2792,7 @@ static int rt5640_suspend(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + rt5640_cancel_work(rt5640); snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); @@ -2654,6 +2815,36 @@ static int rt5640_resume(struct snd_soc_component *component) regcache_cache_only(rt5640->regmap, false); regcache_sync(rt5640->regmap); + if (rt5640->jack) { + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { + snd_soc_component_update_bits(component, + RT5640_DUMMY2, 0x1100, 0x1100); + } else { + if (rt5640->jd_inverted) { + if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) + snd_soc_component_update_bits( + component, RT5640_DUMMY2, + RT5640_IRQ_JD2_MASK | + RT5640_JD2_MASK, + RT5640_IRQ_JD2_NOR | + RT5640_JD2_EN); + + } else { + if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N) + snd_soc_component_update_bits( + component, RT5640_DUMMY2, + RT5640_IRQ_JD2_MASK | + RT5640_JD2_P_MASK | + RT5640_JD2_MASK, + RT5640_IRQ_JD2_NOR | + RT5640_JD2_P_INV | + RT5640_JD2_EN); + } + } + + queue_delayed_work(system_long_wq, &rt5640->jack_work, 0); + } + return 0; } #else @@ -2728,8 +2919,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static const struct regmap_config rt5640_regmap = { @@ -2795,8 +2984,7 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) return 0; } -static int rt5640_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5640_i2c_probe(struct i2c_client *i2c) { struct rt5640_priv *rt5640; int ret; @@ -2856,7 +3044,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, rt5640->hp_mute = true; rt5640->irq = i2c->irq; INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); - INIT_WORK(&rt5640->jack_work, rt5640_jack_work); + INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work); /* Make sure work is stopped on probe-error / remove */ ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640); @@ -2874,7 +3062,7 @@ static struct i2c_driver rt5640_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5640_acpi_match), .of_match_table = of_match_ptr(rt5640_of_match), }, - .probe = rt5640_i2c_probe, + .probe_new = rt5640_i2c_probe, .id_table = rt5640_i2c_id, }; module_i2c_driver(rt5640_i2c_driver); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 2c28f83e338a..f58b88e3325b 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1984,6 +1984,20 @@ #define RT5640_M_MONO_ADC_R_SFT 12 #define RT5640_MCLK_DET (0x1 << 11) +/* General Control 1 (0xfb) */ +#define RT5640_IRQ_JD2_MASK (0x1 << 12) +#define RT5640_IRQ_JD2_SFT 12 +#define RT5640_IRQ_JD2_BP (0x0 << 12) +#define RT5640_IRQ_JD2_NOR (0x1 << 12) +#define RT5640_JD2_P_MASK (0x1 << 10) +#define RT5640_JD2_P_SFT 10 +#define RT5640_JD2_P_NOR (0x0 << 10) +#define RT5640_JD2_P_INV (0x1 << 10) +#define RT5640_JD2_MASK (0x1 << 8) +#define RT5640_JD2_SFT 8 +#define RT5640_JD2_DIS (0x0 << 8) +#define RT5640_JD2_EN (0x1 << 8) + /* Codec Private Register definition */ /* MIC Over current threshold scale factor (0x15) */ @@ -2124,6 +2138,7 @@ struct rt5640_priv { int ldo1_en; /* GPIO for LDO1_EN */ int irq; + int jd_gpio_irq; int sysclk; int sysclk_src; int lrck[RT5640_AIFS]; @@ -2136,6 +2151,8 @@ struct rt5640_priv { bool hp_mute; bool asrc_en; + bool irq_requested; + bool jd_gpio_irq_requested; /* Jack and button detect data */ bool ovcd_irq_enabled; @@ -2145,12 +2162,20 @@ struct rt5640_priv { int release_count; int poll_count; struct delayed_work bp_work; - struct work_struct jack_work; + struct delayed_work jack_work; struct snd_soc_jack *jack; + struct gpio_desc *jd_gpio; unsigned int jd_src; bool jd_inverted; unsigned int ovcd_th; unsigned int ovcd_sf; + bool use_platform_clock; +}; + +struct rt5640_set_jack_data { + int codec_irq_override; + struct gpio_desc *jd_gpio; + bool use_platform_clock; }; int rt5640_dmic_enable(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 197c56047947..620ecbfa4a7a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3534,7 +3534,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = { .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5645_regmap = { @@ -3855,8 +3854,7 @@ static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) return 0; } -static int rt5645_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5645_i2c_probe(struct i2c_client *i2c) { struct rt5645_platform_data *pdata = NULL; const struct dmi_system_id *dmi_data; @@ -3944,7 +3942,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", ret); - return ret; + goto err_enable; } /* @@ -3975,7 +3973,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(rt5645->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - return ret; + goto err_enable; } regmap_write(rt5645->regmap, RT5645_RESET, 0); @@ -4147,20 +4145,23 @@ err_enable: return ret; } -static int rt5645_i2c_remove(struct i2c_client *i2c) +static void rt5645_i2c_remove(struct i2c_client *i2c) { struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); if (i2c->irq) free_irq(i2c->irq, rt5645); + /* + * Since the rt5645_btn_check_callback() can queue jack_detect_work, + * the timer need to be delted first + */ + del_timer_sync(&rt5645->btn_check_timer); + cancel_delayed_work_sync(&rt5645->jack_detect_work); cancel_delayed_work_sync(&rt5645->rcclock_work); - del_timer_sync(&rt5645->btn_check_timer); regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); - - return 0; } static void rt5645_i2c_shutdown(struct i2c_client *i2c) @@ -4183,7 +4184,7 @@ static struct i2c_driver rt5645_i2c_driver = { .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, - .probe = rt5645_i2c_probe, + .probe_new = rt5645_i2c_probe, .remove = rt5645_i2c_remove, .shutdown = rt5645_i2c_shutdown, .id_table = rt5645_i2c_id, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index f302c25688d1..df90af906563 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2161,7 +2161,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5651 = { .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5651_regmap = { @@ -2209,8 +2208,7 @@ MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); * Note this function MUST not look at device-properties, see the comment * above rt5651_apply_properties(). */ -static int rt5651_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5651_i2c_probe(struct i2c_client *i2c) { struct rt5651_priv *rt5651; int ret; @@ -2281,7 +2279,7 @@ static struct i2c_driver rt5651_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5651_acpi_match), .of_match_table = of_match_ptr(rt5651_of_match), }, - .probe = rt5651_i2c_probe, + .probe_new = rt5651_i2c_probe, .id_table = rt5651_i2c_id, }; module_i2c_driver(rt5651_i2c_driver); diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index e1503c2eee81..5e21e3c37ab5 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3801,7 +3801,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5659 = { .set_pll = rt5659_set_component_pll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -4093,8 +4092,7 @@ static void rt5659_intel_hd_header_probe_setup(struct rt5659_priv *rt5659) RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN); } -static int rt5659_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5659_i2c_probe(struct i2c_client *i2c) { struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5659_priv *rt5659; @@ -4342,7 +4340,7 @@ static struct i2c_driver rt5659_i2c_driver = { .of_match_table = of_match_ptr(rt5659_of_match), .acpi_match_table = ACPI_PTR(rt5659_acpi_match), }, - .probe = rt5659_i2c_probe, + .probe_new = rt5659_i2c_probe, .shutdown = rt5659_i2c_shutdown, .id_table = rt5659_i2c_id, }; diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 3b50fb29864e..341baa29fdb1 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1208,7 +1208,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5660 = { .num_dapm_routes = ARRAY_SIZE(rt5660_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5660_regmap = { @@ -1266,8 +1265,7 @@ static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev) return 0; } -static int rt5660_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5660_i2c_probe(struct i2c_client *i2c) { struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5660_priv *rt5660; @@ -1343,7 +1341,7 @@ static struct i2c_driver rt5660_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5660_acpi_match), .of_match_table = of_match_ptr(rt5660_of_match), }, - .probe = rt5660_i2c_probe, + .probe_new = rt5660_i2c_probe, .id_table = rt5660_i2c_id, }; module_i2c_driver(rt5660_i2c_driver); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 0389b2bb360e..f73751dbde30 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3258,7 +3258,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = { .set_jack = rt5663_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5663_v2_regmap = { @@ -3461,6 +3460,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) { int table_size; + int ret; device_property_read_u32(dev, "realtek,dc_offset_l_manual", &rt5663->pdata.dc_offset_l_manual); @@ -3477,16 +3477,19 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) table_size = sizeof(struct impedance_mapping_table) * rt5663->pdata.impedance_sensing_num; rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL); - device_property_read_u32_array(dev, + if (!rt5663->imp_table) + return -ENOMEM; + ret = device_property_read_u32_array(dev, "realtek,impedance_sensing_table", (u32 *)rt5663->imp_table, table_size); + if (ret) + return ret; } return 0; } -static int rt5663_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5663_i2c_probe(struct i2c_client *i2c) { struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; @@ -3504,8 +3507,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, if (pdata) rt5663->pdata = *pdata; - else - rt5663_parse_dp(rt5663, &i2c->dev); + else { + ret = rt5663_parse_dp(rt5663, &i2c->dev); + if (ret) + return ret; + } for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) rt5663->supplies[i].supply = rt5663_supply_names[i]; @@ -3704,7 +3710,7 @@ err_enable: return ret; } -static int rt5663_i2c_remove(struct i2c_client *i2c) +static void rt5663_i2c_remove(struct i2c_client *i2c) { struct rt5663_priv *rt5663 = i2c_get_clientdata(i2c); @@ -3712,8 +3718,6 @@ static int rt5663_i2c_remove(struct i2c_client *i2c) free_irq(i2c->irq, rt5663); regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); - - return 0; } static void rt5663_i2c_shutdown(struct i2c_client *client) @@ -3729,7 +3733,7 @@ static struct i2c_driver rt5663_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5663_acpi_match), .of_match_table = of_match_ptr(rt5663_of_match), }, - .probe = rt5663_i2c_probe, + .probe_new = rt5663_i2c_probe, .remove = rt5663_i2c_remove, .shutdown = rt5663_i2c_shutdown, .id_table = rt5663_i2c_id, diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 33e889802ff8..6e66cc218fa8 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4617,7 +4617,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5665 = { .set_jack = rt5665_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; @@ -4757,8 +4756,7 @@ static void rt5665_calibrate_handler(struct work_struct *work) rt5665_calibrate(rt5665); } -static int rt5665_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5665_i2c_probe(struct i2c_client *i2c) { struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5665_priv *rt5665; @@ -4970,7 +4968,7 @@ static struct i2c_driver rt5665_i2c_driver = { .of_match_table = of_match_ptr(rt5665_of_match), .acpi_match_table = ACPI_PTR(rt5665_acpi_match), }, - .probe = rt5665_i2c_probe, + .probe_new = rt5665_i2c_probe, .shutdown = rt5665_i2c_shutdown, .id_table = rt5665_i2c_id, }; diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index fb09715bf932..beb0951ff680 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -1022,11 +1022,13 @@ static void rt5668_jack_detect_handler(struct work_struct *work) container_of(work, struct rt5668_priv, jack_detect_work.work); int val, btn_type; - while (!rt5668->component) - usleep_range(10000, 15000); - - while (!rt5668->component->card->instantiated) - usleep_range(10000, 15000); + if (!rt5668->component || !rt5668->component->card || + !rt5668->component->card->instantiated) { + /* card not yet ready, try later */ + mod_delayed_work(system_power_efficient_wq, + &rt5668->jack_detect_work, msecs_to_jiffies(15)); + return; + } mutex_lock(&rt5668->calibrate_mutex); @@ -2360,7 +2362,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5668 = { .set_jack = rt5668_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5668_regmap = { @@ -2451,8 +2452,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) } -static int rt5668_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5668_i2c_probe(struct i2c_client *i2c) { struct rt5668_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5668_priv *rt5668; @@ -2618,7 +2618,7 @@ static struct i2c_driver rt5668_i2c_driver = { .of_match_table = of_match_ptr(rt5668_of_match), .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, - .probe = rt5668_i2c_probe, + .probe_new = rt5668_i2c_probe, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index ce7684752bb0..ebac6caeb40a 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2852,7 +2852,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5670 = { .num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5670_regmap = { @@ -3046,8 +3045,7 @@ const char *rt5670_components(void) } EXPORT_SYMBOL_GPL(rt5670_components); -static int rt5670_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5670_i2c_probe(struct i2c_client *i2c) { struct rt5670_priv *rt5670; int ret; @@ -3322,11 +3320,9 @@ err: return ret; } -static int rt5670_i2c_remove(struct i2c_client *i2c) +static void rt5670_i2c_remove(struct i2c_client *i2c) { pm_runtime_disable(&i2c->dev); - - return 0; } static struct i2c_driver rt5670_i2c_driver = { @@ -3334,7 +3330,7 @@ static struct i2c_driver rt5670_i2c_driver = { .name = "rt5670", .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, - .probe = rt5670_i2c_probe, + .probe_new = rt5670_i2c_probe, .remove = rt5670_i2c_remove, .id_table = rt5670_i2c_id, }; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 4a8c267d4fbc..c26395f42d8e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5189,7 +5189,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5677 = { .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config rt5677_regmap_physical = { @@ -5694,11 +5693,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) rt5677_dai, ARRAY_SIZE(rt5677_dai)); } -static int rt5677_i2c_remove(struct i2c_client *i2c) +static void rt5677_i2c_remove(struct i2c_client *i2c) { rt5677_free_gpio(i2c); - - return 0; } static struct i2c_driver rt5677_i2c_driver = { diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 20e0f90ea498..2935c1bb81f3 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work) struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv, jd_check_work.work); - if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) - & RT5682_JDH_RS_MASK) { + if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK) /* jack out */ - rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0); - - snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3); - } else { + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, 0); + else schedule_delayed_work(&rt5682->jd_check_work, 500); - } } static irqreturn_t rt5682_irq(int irq, void *data) @@ -124,8 +118,7 @@ static void rt5682_i2c_disable_regulators(void *data) regulator_bulk_disable(ARRAY_SIZE(rt5682->supplies), rt5682->supplies); } -static int rt5682_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5682_i2c_probe(struct i2c_client *i2c) { struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5682_priv *rt5682; @@ -198,7 +191,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, } mutex_init(&rt5682->calibrate_mutex); - mutex_init(&rt5682->jdet_mutex); rt5682_calibrate(rt5682); rt5682_apply_patch_list(rt5682, &i2c->dev); @@ -310,11 +302,9 @@ static void rt5682_i2c_shutdown(struct i2c_client *client) rt5682_reset(rt5682); } -static int rt5682_i2c_remove(struct i2c_client *client) +static void rt5682_i2c_remove(struct i2c_client *client) { rt5682_i2c_shutdown(client); - - return 0; } static const struct of_device_id rt5682_of_match[] = { @@ -342,7 +332,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = rt5682_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe = rt5682_i2c_probe, + .probe_new = rt5682_i2c_probe, .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 31a4f286043e..c1a94229dc7e 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -272,7 +272,7 @@ static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt5682_sdw_ops = { .hw_params = rt5682_sdw_hw_params, .hw_free = rt5682_sdw_hw_free, - .set_sdw_stream = rt5682_set_sdw_stream, + .set_stream = rt5682_set_sdw_stream, .shutdown = rt5682_sdw_shutdown, }; @@ -719,9 +719,12 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) { struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); - if (rt5682 && rt5682->hw_init) + if (rt5682->hw_init) cancel_delayed_work_sync(&rt5682->jack_detect_work); + if (rt5682->first_hw_init) + pm_runtime_disable(&slave->dev); + return 0; } @@ -790,6 +793,8 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) msecs_to_jiffies(RT5682_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 5224123d0d3b..2df95e792900 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -922,7 +922,7 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component, * * Returns detect status. */ -int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) +static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm = &component->dapm; @@ -1007,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type); return rt5682->jack_type; } -EXPORT_SYMBOL_GPL(rt5682_headset_detect); static int rt5682_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) @@ -1090,15 +1089,29 @@ void rt5682_jack_detect_handler(struct work_struct *work) { struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv, jack_detect_work.work); + struct snd_soc_dapm_context *dapm; int val, btn_type; - while (!rt5682->component) - usleep_range(10000, 15000); + if (!rt5682->component || !rt5682->component->card || + !rt5682->component->card->instantiated) { + /* card not yet ready, try later */ + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, msecs_to_jiffies(15)); + return; + } + + if (rt5682->is_sdw) { + if (pm_runtime_status_suspended(rt5682->slave->dev.parent)) { + dev_dbg(&rt5682->slave->dev, + "%s: parent device is pm_runtime_status_suspended, skipping jack detection\n", + __func__); + return; + } + } - while (!rt5682->component->card->instantiated) - usleep_range(10000, 15000); + dapm = snd_soc_component_get_dapm(rt5682->component); - mutex_lock(&rt5682->jdet_mutex); + snd_soc_dapm_mutex_lock(dapm); mutex_lock(&rt5682->calibrate_mutex); val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) @@ -1158,6 +1171,9 @@ void rt5682_jack_detect_handler(struct work_struct *work) rt5682->irq_work_delay_time = 50; } + mutex_unlock(&rt5682->calibrate_mutex); + snd_soc_dapm_mutex_unlock(dapm); + snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | @@ -1170,9 +1186,6 @@ void rt5682_jack_detect_handler(struct work_struct *work) else cancel_delayed_work_sync(&rt5682->jd_check_work); } - - mutex_unlock(&rt5682->calibrate_mutex); - mutex_unlock(&rt5682->jdet_mutex); } EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler); @@ -1522,7 +1535,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1534,17 +1546,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_DEPOP_1, 0x60, 0x60); snd_soc_component_update_bits(component, RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); - - mutex_lock(&rt5682->jdet_mutex); - snd_soc_component_update_bits(component, RT5682_HP_CTRL_2, RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN, RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN); usleep_range(5000, 10000); snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1, RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L); - - mutex_unlock(&rt5682->jdet_mutex); break; case SND_SOC_DAPM_POST_PMD: @@ -2824,14 +2831,11 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate, for_each_component_dais(component, dai) if (dai->id == RT5682_AIF1) - break; - if (!dai) { - dev_err(rt5682->i2c_dev, "dai %d not found in component\n", - RT5682_AIF1); - return -ENODEV; - } + return rt5682_set_bclk1_ratio(dai, factor); - return rt5682_set_bclk1_ratio(dai, factor); + dev_err(rt5682->i2c_dev, "dai %d not found in component\n", + RT5682_AIF1); + return -ENODEV; } static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = { @@ -2858,7 +2862,6 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682) for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) { struct clk_init_data init = { }; - struct clk_parent_data parent_data; const struct clk_hw *parent; dai_clk_hw = &rt5682->dai_clks_hw[i]; @@ -2867,10 +2870,8 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682) case RT5682_DAI_WCLK_IDX: /* Make MCLK the parent of WCLK */ if (rt5682->mclk) { - parent_data = (struct clk_parent_data){ - .fw_name = "mclk", - }; - init.parent_data = &parent_data; + parent = __clk_get_hw(rt5682->mclk); + init.parent_hws = &parent; init.num_parents = 1; } break; @@ -3063,7 +3064,6 @@ const struct snd_soc_component_driver rt5682_soc_component_dev = { .set_jack = rt5682_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(rt5682_soc_component_dev); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index c917c76200ea..52ff0d9c36c5 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1463,7 +1463,6 @@ struct rt5682_priv { int jack_type; int irq_work_delay_time; - struct mutex jdet_mutex; }; extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES]; @@ -1473,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component, void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev); -int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert); void rt5682_jack_detect_handler(struct work_struct *work); bool rt5682_volatile_register(struct device *dev, unsigned int reg); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index d49a4f68566d..80c673aa14db 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -42,8 +42,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = { }; static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = { - "AVDD", - "MICVDD", + [RT5682S_SUPPLY_AVDD] = "AVDD", + [RT5682S_SUPPLY_MICVDD] = "MICVDD", }; static const struct reg_sequence patch_list[] = { @@ -644,8 +644,7 @@ enum { SAR_PWR_SAVING, }; -static void rt5682s_sar_power_mode(struct snd_soc_component *component, - int mode, int jd_step) +static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode) { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); @@ -675,16 +674,17 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, RT5682S_CTRL_MB1_FSM | RT5682S_CTRL_MB2_FSM); - if (!jd_step) { - snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, - RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_SEL_MB1_2_AUTO); - usleep_range(5000, 5500); - snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, - RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK, - RT5682S_SAR_BUTDET_EN | RT5682S_SAR_BUTDET_POW_NORM); - } + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_SEL_MB1_2_AUTO); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK, + RT5682S_SAR_BUTDET_EN | RT5682S_SAR_BUTDET_POW_NORM); break; case SAR_PWR_OFF: + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, + RT5682S_CTRL_MB1_FSM | RT5682S_CTRL_MB2_FSM); snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | @@ -702,6 +702,10 @@ static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) { snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_BTN); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_EN | + RT5682S_SAR_BUTDET_POW_NORM | RT5682S_SAR_SEL_MB1_2_AUTO); snd_soc_component_write(component, RT5682S_IL_CMD_1, 0x0040); snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, RT5682S_4BTN_IL_MASK | RT5682S_4BTN_IL_RST_MASK, @@ -718,6 +722,10 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component) RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | + RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU); } /** @@ -731,6 +739,7 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component) */ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert) { + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); unsigned int val, count; int jack_type = 0; @@ -753,7 +762,8 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_ RT5682S_OSW_L_DIS | RT5682S_OSW_R_DIS); snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); - rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 1); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_EN); snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); usleep_range(45000, 50000); @@ -779,9 +789,8 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_ RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_EN); snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, RT5682S_SAR_SEL_MB1_2_MASK, val << RT5682S_SAR_SEL_MB1_2_SFT); - if (!snd_soc_dapm_get_pin_status(&component->dapm, "SAR")) - rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 1); rt5682s_enable_push_button_irq(component); + rt5682s_sar_power_mode(component, SAR_PWR_SAVING); break; default: jack_type = SND_JACK_HEADPHONE; @@ -792,17 +801,15 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_ RT5682S_OSW_L_EN | RT5682S_OSW_R_EN); usleep_range(35000, 40000); } else { - rt5682s_sar_power_mode(component, SAR_PWR_OFF, 1); + rt5682s_sar_power_mode(component, SAR_PWR_OFF); rt5682s_disable_push_button_irq(component); snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); - if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); - if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2")) + if (!rt5682s->wclk_enabled) { snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0); + } snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, RT5682S_PWR_CBJ, 0); @@ -822,16 +829,22 @@ static void rt5682s_jack_detect_handler(struct work_struct *work) { struct rt5682s_priv *rt5682s = container_of(work, struct rt5682s_priv, jack_detect_work.work); + struct snd_soc_dapm_context *dapm; int val, btn_type; - while (!rt5682s->component) - usleep_range(10000, 15000); + if (!rt5682s->component || !rt5682s->component->card || + !rt5682s->component->card->instantiated) { + /* card not yet ready, try later */ + mod_delayed_work(system_power_efficient_wq, + &rt5682s->jack_detect_work, msecs_to_jiffies(15)); + return; + } - while (!rt5682s->component->card->instantiated) - usleep_range(10000, 15000); + dapm = snd_soc_component_get_dapm(rt5682s->component); - mutex_lock(&rt5682s->jdet_mutex); + snd_soc_dapm_mutex_lock(dapm); mutex_lock(&rt5682s->calibrate_mutex); + mutex_lock(&rt5682s->wclk_mutex); val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) & RT5682S_JDH_RS_MASK; @@ -887,6 +900,10 @@ static void rt5682s_jack_detect_handler(struct work_struct *work) rt5682s->irq_work_delay_time = 50; } + mutex_unlock(&rt5682s->wclk_mutex); + mutex_unlock(&rt5682s->calibrate_mutex); + snd_soc_dapm_mutex_unlock(dapm); + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); @@ -896,9 +913,6 @@ static void rt5682s_jack_detect_handler(struct work_struct *work) schedule_delayed_work(&rt5682s->jd_check_work, 0); else cancel_delayed_work_sync(&rt5682s->jd_check_work); - - mutex_unlock(&rt5682s->calibrate_mutex); - mutex_unlock(&rt5682s->jdet_mutex); } static void rt5682s_jd_check_handler(struct work_struct *work) @@ -906,14 +920,9 @@ static void rt5682s_jd_check_handler(struct work_struct *work) struct rt5682s_priv *rt5682s = container_of(work, struct rt5682s_priv, jd_check_work.work); - if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) - & RT5682S_JDH_RS_MASK) { + if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) & RT5682S_JDH_RS_MASK) { /* jack out */ - rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 0); - - snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3); + schedule_delayed_work(&rt5682s->jack_detect_work, 0); } else { schedule_delayed_work(&rt5682s->jd_check_work, 500); } @@ -1146,29 +1155,52 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, return 0; } -static int set_filter_clk(struct snd_soc_dapm_widget *w, + +static int rt5682s_set_pllb_power(struct rt5682s_priv *rt5682s, int on) +{ + struct snd_soc_component *component = rt5682s->component; + + if (on) { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLB, RT5682S_RSTB_PLLB); + } else { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | + RT5682S_RSTB_PLLB | RT5682S_PWR_PLLB, 0); + } + + return 0; +} + +static int set_pllb_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - int ref, val, reg, idx; - static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; - static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + int on = 0; - val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) - & RT5682S_GP4_PIN_MASK; + if (rt5682s->wclk_enabled) + return 0; - if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) - ref = 256 * rt5682s->lrck[RT5682S_AIF2]; - else - ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + if (SND_SOC_DAPM_EVENT_ON(event)) + on = 1; - idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); + rt5682s_set_pllb_power(rt5682s, on); - if (w->shift == RT5682S_PWR_ADC_S1F_BIT) - reg = RT5682S_PLL_TRACK_3; - else - reg = RT5682S_PLL_TRACK_2; + return 0; +} + +static void rt5682s_set_filter_clk(struct rt5682s_priv *rt5682s, int reg, int ref) +{ + struct snd_soc_component *component = rt5682s->component; + int idx; + static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + + idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); snd_soc_component_update_bits(component, reg, RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT); @@ -1182,6 +1214,29 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK, (idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT)); +} + +static int set_filter_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int ref, reg, val; + + val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) + & RT5682S_GP4_PIN_MASK; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) + ref = 256 * rt5682s->lrck[RT5682S_AIF2]; + else + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT) + reg = RT5682S_PLL_TRACK_3; + else + reg = RT5682S_PLL_TRACK_2; + + rt5682s_set_filter_clk(rt5682s, reg, ref); return 0; } @@ -1210,13 +1265,9 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - if (!rt5682s->jack_type) { - if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); - if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + if (!rt5682s->jack_type && !rt5682s->wclk_enabled) { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0); } break; } @@ -1224,41 +1275,58 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, return 0; } -static int set_i2s_clk(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static void rt5682s_set_i2s(struct rt5682s_priv *rt5682s, int id, int on) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - int pre_div, id; - unsigned int reg, mask, sft; - - if (event != SND_SOC_DAPM_PRE_PMU) - return 0; - - if (w->shift == RT5682S_PWR_I2S2_BIT) { - id = RT5682S_AIF2; - reg = RT5682S_I2S2_M_CLK_CTRL_1; - mask = RT5682S_I2S2_M_D_MASK; - sft = RT5682S_I2S2_M_D_SFT; + struct snd_soc_component *component = rt5682s->component; + int pre_div; + unsigned int p_reg, p_mask, p_sft; + unsigned int c_reg, c_mask, c_sft; + + if (id == RT5682S_AIF1) { + c_reg = RT5682S_ADDA_CLK_1; + c_mask = RT5682S_I2S_M_D_MASK; + c_sft = RT5682S_I2S_M_D_SFT; + p_reg = RT5682S_PWR_DIG_1; + p_mask = RT5682S_PWR_I2S1; + p_sft = RT5682S_PWR_I2S1_BIT; } else { - id = RT5682S_AIF1; - reg = RT5682S_ADDA_CLK_1; - mask = RT5682S_I2S_M_D_MASK; - sft = RT5682S_I2S_M_D_SFT; + c_reg = RT5682S_I2S2_M_CLK_CTRL_1; + c_mask = RT5682S_I2S2_M_D_MASK; + c_sft = RT5682S_I2S2_M_D_SFT; + p_reg = RT5682S_PWR_DIG_1; + p_mask = RT5682S_PWR_I2S2; + p_sft = RT5682S_PWR_I2S2_BIT; } - if (!rt5682s->master[id]) - return 0; + if (on && rt5682s->master[id]) { + pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); + if (pre_div < 0) { + dev_err(component->dev, "get pre_div failed\n"); + return; + } - pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); - if (pre_div < 0) { - dev_err(component->dev, "get pre_div failed\n"); - return -EINVAL; + dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", + rt5682s->lrck[id], pre_div, id); + snd_soc_component_update_bits(component, c_reg, c_mask, pre_div << c_sft); } - dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", - rt5682s->lrck[id], pre_div, id); - snd_soc_component_update_bits(component, reg, mask, pre_div << sft); + snd_soc_component_update_bits(component, p_reg, p_mask, on << p_sft); +} + +static int set_i2s_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int on = 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) + on = 1; + + if (!strcmp(w->name, "I2S1") && !rt5682s->wclk_enabled) + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, on); + else if (!strcmp(w->name, "I2S2")) + rt5682s_set_i2s(rt5682s, RT5682S_AIF2, on); return 0; } @@ -1321,7 +1389,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1337,8 +1404,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_11, 0x6666); snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_12, 0xa82a); - mutex_lock(&rt5682s->jdet_mutex); - snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | RT5682S_HPO_SEL_IP_EN_SW, RT5682S_HPO_L_PATH_EN | @@ -1346,8 +1411,6 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, usleep_range(5000, 10000); snd_soc_component_update_bits(component, RT5682S_HP_AMP_DET_CTL_1, RT5682S_CP_SW_SIZE_MASK, RT5682S_CP_SW_SIZE_L | RT5682S_CP_SW_SIZE_S); - - mutex_unlock(&rt5682s->jdet_mutex); break; case SND_SOC_DAPM_POST_PMD: @@ -1367,6 +1430,31 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5682s_stereo1_adc_mixl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int delay = 0; + + if (rt5682s->pdata.amic_delay) + delay = rt5682s->pdata.amic_delay; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(delay); + snd_soc_component_update_bits(component, RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE, 0); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE, RT5682S_L_MUTE); + break; + } + + return 0; +} + static int sar_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1378,10 +1466,10 @@ static int sar_power_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 0); + rt5682s_sar_power_mode(component, SAR_PWR_NORMAL); break; case SND_SOC_DAPM_POST_PMD: - rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 0); + rt5682s_sar_power_mode(component, SAR_PWR_SAVING); break; } @@ -1587,26 +1675,18 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3, RT5682S_PWR_LDO_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0), /* PLL Powers */ SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3, RT5682S_RSTB_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3, - RT5682S_RSTB_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLLB", SND_SOC_NOPM, 0, 0, + set_pllb_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, @@ -1680,9 +1760,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { /* ADC Mixer */ SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682S_PWR_DIG_2, RT5682S_PWR_ADC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682S_STO1_ADC_DIG_VOL, - RT5682S_L_MUTE_SFT, 1, rt5682s_sto1_adc_l_mix, - ARRAY_SIZE(rt5682s_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER_E("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_adc_l_mix, ARRAY_SIZE(rt5682s_sto1_adc_l_mix), + rt5682s_stereo1_adc_mixl_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682S_STO1_ADC_DIG_VOL, RT5682S_R_MUTE_SFT, 1, rt5682s_sto1_adc_r_mix, ARRAY_SIZE(rt5682s_sto1_adc_r_mix)), @@ -1691,10 +1772,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), /* Digital Interface */ - SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT, - 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT, - 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("I2S1", SND_SOC_NOPM, 0, 0, + set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("I2S2", SND_SOC_NOPM, 0, 0, + set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -1772,9 +1853,6 @@ static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = { {"PLLA", NULL, "PLLA_LDO"}, {"PLLA", NULL, "PLLA_BIAS"}, {"PLLA", NULL, "PLLA_RST"}, - {"PLLB", NULL, "PLLB_LDO"}, - {"PLLB", NULL, "PLLB_BIAS"}, - {"PLLB", NULL, "PLLB_RST"}, /*ASRC*/ {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, @@ -1903,7 +1981,7 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; - unsigned int cl, val = 0; + unsigned int cl, val = 0, tx_slotnum; if (tx_mask || rx_mask) snd_soc_component_update_bits(component, @@ -1912,6 +1990,16 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, snd_soc_component_update_bits(component, RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, 0); + /* Tx slot configuration */ + tx_slotnum = hweight_long(tx_mask); + if (tx_slotnum) { + if (tx_slotnum > slots) { + dev_err(component->dev, "Invalid or oversized Tx slots.\n"); + return -EINVAL; + } + val |= (tx_slotnum - 1) << RT5682S_TDM_ADC_DL_SFT; + } + switch (slots) { case 4: val |= RT5682S_TDM_TX_CH_4; @@ -1932,7 +2020,8 @@ static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, } snd_soc_component_update_bits(component, RT5682S_TDM_CTRL, - RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK, val); + RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK | + RT5682S_TDM_ADC_DL_MASK, val); switch (slot_width) { case 8: @@ -2402,12 +2491,15 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component, RT5682S_PWR_LDO, RT5682S_PWR_LDO); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, - RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); break; case SND_SOC_BIAS_OFF: - regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, - RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, RT5682S_PWR_LDO, 0); + if (!rt5682s->wclk_enabled) + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, 0); break; case SND_SOC_BIAS_ON: break; @@ -2435,30 +2527,34 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682s->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ref, reg; if (!rt5682s_clk_check(rt5682s)) return -EINVAL; - snd_soc_dapm_mutex_lock(dapm); - - snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); - snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, - RT5682S_PWR_MB, RT5682S_PWR_MB); + mutex_lock(&rt5682s->wclk_mutex); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2"); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, - RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2); + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB); usleep_range(15000, 20000); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_FV2, RT5682S_PWR_FV2); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1"); - /* Only need to power PLLB due to the rate set restriction */ - snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); - snd_soc_dapm_sync_unlocked(dapm); + /* Set and power on I2S1 */ + snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 1); - snd_soc_dapm_mutex_unlock(dapm); + /* Only need to power on PLLB due to the rate set restriction */ + reg = RT5682S_PLL_TRACK_2; + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + rt5682s_set_filter_clk(rt5682s, reg, ref); + rt5682s_set_pllb_power(rt5682s, 1); + + rt5682s->wclk_enabled = 1; + + mutex_unlock(&rt5682s->wclk_mutex); return 0; } @@ -2468,24 +2564,27 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682s->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); if (!rt5682s_clk_check(rt5682s)) return; - snd_soc_dapm_mutex_lock(dapm); + mutex_lock(&rt5682s->wclk_mutex); - snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2"); if (!rt5682s->jack_type) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0); - snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1"); - snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); - snd_soc_dapm_sync_unlocked(dapm); + /* Power down I2S1 */ + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 0); + snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, 0); - snd_soc_dapm_mutex_unlock(dapm); + /* Power down PLLB */ + rt5682s_set_pllb_power(rt5682s, 0); + + rt5682s->wclk_enabled = 0; + + mutex_unlock(&rt5682s->wclk_mutex); } static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, @@ -2658,14 +2757,11 @@ static int rt5682s_bclk_set_rate(struct clk_hw *hw, unsigned long rate, for_each_component_dais(component, dai) if (dai->id == RT5682S_AIF1) - break; - if (!dai) { - dev_err(component->dev, "dai %d not found in component\n", - RT5682S_AIF1); - return -ENODEV; - } + return rt5682s_set_bclk1_ratio(dai, factor); - return rt5682s_set_bclk1_ratio(dai, factor); + dev_err(component->dev, "dai %d not found in component\n", + RT5682S_AIF1); + return -ENODEV; } static const struct clk_ops rt5682s_dai_clk_ops[RT5682S_DAI_NUM_CLKS] = { @@ -2779,19 +2875,10 @@ static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component) static int rt5682s_probe(struct snd_soc_component *component) { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm = &component->dapm; - int ret; rt5682s->component = component; - ret = rt5682s_dai_probe_clks(component); - if (ret) - return ret; - - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); - snd_soc_dapm_disable_pin(dapm, "Vref2"); - snd_soc_dapm_sync(dapm); - return 0; + return rt5682s_dai_probe_clks(component); } static void rt5682s_remove(struct snd_soc_component *component) @@ -2809,9 +2896,8 @@ static int rt5682s_suspend(struct snd_soc_component *component) cancel_delayed_work_sync(&rt5682s->jack_detect_work); cancel_delayed_work_sync(&rt5682s->jd_check_work); - if (rt5682s->hs_jack && rt5682s->jack_type == SND_JACK_HEADSET) - snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, - RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); + if (rt5682s->hs_jack) + rt5682s->jack_type = rt5682s_headset_detect(component, 0); regcache_cache_only(rt5682s->regmap, true); regcache_mark_dirty(rt5682s->regmap); @@ -2827,8 +2913,6 @@ static int rt5682s_resume(struct snd_soc_component *component) regcache_sync(rt5682s->regmap); if (rt5682s->hs_jack) { - rt5682s->jack_type = 0; - rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 0); mod_delayed_work(system_power_efficient_wq, &rt5682s->jack_detect_work, msecs_to_jiffies(0)); } @@ -2870,7 +2954,6 @@ static const struct snd_soc_component_driver rt5682s_soc_component_dev = { .set_jack = rt5682s_set_jack_detect, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) @@ -2885,6 +2968,8 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) &rt5682s->pdata.dmic_clk_rate); device_property_read_u32(dev, "realtek,dmic-delay-ms", &rt5682s->pdata.dmic_delay); + device_property_read_u32(dev, "realtek,amic-delay-ms", + &rt5682s->pdata.amic_delay); rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, "realtek,ldo1-en-gpios", 0); @@ -2997,12 +3082,21 @@ static struct snd_soc_dai_driver rt5682s_dai[] = { static void rt5682s_i2c_disable_regulators(void *data) { struct rt5682s_priv *rt5682s = data; + struct device *dev = regmap_get_device(rt5682s->regmap); + int ret; - regulator_bulk_disable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_AVDD].consumer); + if (ret) + dev_err(dev, "Failed to disable supply AVDD: %d\n", ret); + + usleep_range(1000, 1500); + + ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer); + if (ret) + dev_err(dev, "Failed to disable supply MICVDD: %d\n", ret); } -static int rt5682s_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int rt5682s_i2c_probe(struct i2c_client *i2c) { struct rt5682s_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5682s_priv *rt5682s; @@ -3043,9 +3137,16 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c, if (ret) return ret; - ret = regulator_bulk_enable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer); if (ret) { - dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + dev_err(&i2c->dev, "Failed to enable supply MICVDD: %d\n", ret); + return ret; + } + usleep_range(1000, 1500); + + ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_AVDD].consumer); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supply AVDD: %d\n", ret); return ret; } @@ -3073,7 +3174,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c, mutex_init(&rt5682s->calibrate_mutex); mutex_init(&rt5682s->sar_mutex); - mutex_init(&rt5682s->jdet_mutex); + mutex_init(&rt5682s->wclk_mutex); rt5682s_calibrate(rt5682s); regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2, @@ -3155,11 +3256,9 @@ static void rt5682s_i2c_shutdown(struct i2c_client *client) rt5682s_reset(rt5682s); } -static int rt5682s_i2c_remove(struct i2c_client *client) +static void rt5682s_i2c_remove(struct i2c_client *client) { rt5682s_i2c_shutdown(client); - - return 0; } static const struct of_device_id rt5682s_of_match[] = { @@ -3187,7 +3286,7 @@ static struct i2c_driver rt5682s_i2c_driver = { .acpi_match_table = rt5682s_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe = rt5682s_i2c_probe, + .probe_new = rt5682s_i2c_probe, .remove = rt5682s_i2c_remove, .shutdown = rt5682s_i2c_shutdown, .id_table = rt5682s_i2c_id, diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 1bf2ef7ce578..45464a041765 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -899,6 +899,7 @@ #define RT5682S_TDM_RX_CH_8 (0x3 << 8) #define RT5682S_TDM_ADC_LCA_MASK (0x7 << 4) #define RT5682S_TDM_ADC_LCA_SFT 4 +#define RT5682S_TDM_ADC_DL_MASK (0x3 << 0) #define RT5682S_TDM_ADC_DL_SFT 0 /* TDM control 2 (0x007a) */ @@ -1434,7 +1435,11 @@ struct pll_calc_map { bool sel_ps; }; -#define RT5682S_NUM_SUPPLIES 2 +enum { + RT5682S_SUPPLY_AVDD, + RT5682S_SUPPLY_MICVDD, + RT5682S_NUM_SUPPLIES, +}; struct rt5682s_priv { struct snd_soc_component *component; @@ -1446,7 +1451,7 @@ struct rt5682s_priv { struct delayed_work jd_check_work; struct mutex calibrate_mutex; struct mutex sar_mutex; - struct mutex jdet_mutex; + struct mutex wclk_mutex; #ifdef CONFIG_COMMON_CLK struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS]; @@ -1466,6 +1471,7 @@ struct rt5682s_priv { int jack_type; int irq_work_delay_time; + int wclk_enabled; }; int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index bda594899664..96fc5f36d0d0 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -13,6 +13,7 @@ #include <linux/soundwire/sdw_type.h> #include <linux/soundwire/sdw_registers.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/soc.h> #include "rt700.h" @@ -463,11 +464,14 @@ static int rt700_sdw_remove(struct sdw_slave *slave) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); - if (rt700 && rt700->hw_init) { + if (rt700->hw_init) { cancel_delayed_work_sync(&rt700->jack_detect_work); cancel_delayed_work_sync(&rt700->jack_btn_check_work); } + if (rt700->first_hw_init) + pm_runtime_disable(&slave->dev); + return 0; } @@ -538,6 +542,8 @@ static int __maybe_unused rt700_dev_resume(struct device *dev) msecs_to_jiffies(RT700_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 921382724f9c..055c3ae974d8 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -162,7 +162,7 @@ static void rt700_jack_detect_handler(struct work_struct *work) if (!rt700->hs_jack) return; - if (!rt700->component->card->instantiated) + if (!rt700->component->card || !rt700->component->card->instantiated) return; reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; @@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + int ret; rt700->hs_jack = hs_jack; - if (!rt700->hw_init) { - dev_dbg(&rt700->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt700_jack_init(rt700); + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -808,9 +818,14 @@ static const struct snd_soc_dapm_route rt700_audio_map[] = { static int rt700_probe(struct snd_soc_component *component) { struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + int ret; rt700->component = component; + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; } @@ -853,6 +868,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt700 = { .dapm_routes = rt700_audio_map, .num_dapm_routes = ARRAY_SIZE(rt700_audio_map), .set_jack = rt700_set_jack_detect, + .endianness = 1, }; static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1005,7 +1021,7 @@ static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt700_ops = { .hw_params = rt700_pcm_hw_params, .hw_free = rt700_pcm_hw_free, - .set_sdw_stream = rt700_set_sdw_stream, + .set_stream = rt700_set_sdw_stream, .shutdown = rt700_shutdown, }; @@ -1114,6 +1130,11 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, mutex_init(&rt700->disable_irq_lock); + INIT_DELAYED_WORK(&rt700->jack_detect_work, + rt700_jack_detect_handler); + INIT_DELAYED_WORK(&rt700->jack_btn_check_work, + rt700_btn_check_handler); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1208,13 +1229,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - if (!rt700->first_hw_init) { - INIT_DELAYED_WORK(&rt700->jack_detect_work, - rt700_jack_detect_handler); - INIT_DELAYED_WORK(&rt700->jack_btn_check_work, - rt700_btn_check_handler); - } - /* * if set_jack callback occurred early than io_init, * we set up the jack detection function now diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index aaf5af153d3f..4120842fe699 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -11,6 +11,7 @@ #include <linux/mod_devicetable.h> #include <linux/soundwire/sdw_registers.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include "rt711-sdca.h" #include "rt711-sdca-sdw.h" @@ -364,11 +365,17 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave) { struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); - if (rt711 && rt711->hw_init) { + if (rt711->hw_init) { cancel_delayed_work_sync(&rt711->jack_detect_work); cancel_delayed_work_sync(&rt711->jack_btn_check_work); } + if (rt711->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt711->calibrate_mutex); + mutex_destroy(&rt711->disable_irq_lock); + return 0; } @@ -442,6 +449,8 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) msecs_to_jiffies(RT711_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 2e992589f1e4..925268121901 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711, ret = regmap_write(regmap, addr, value); if (ret < 0) - dev_err(rt711->component->dev, + dev_err(&rt711->slave->dev, "Failed to set private value: %06x <= %04x ret=%d\n", addr, value, ret); @@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711, ret = regmap_read(regmap, addr, value); if (ret < 0) - dev_err(rt711->component->dev, + dev_err(&rt711->slave->dev, "Failed to get private value: %06x => %04x ret=%d\n", addr, *value, ret); @@ -294,7 +294,7 @@ static void rt711_sdca_jack_detect_handler(struct work_struct *work) if (!rt711->hs_jack) return; - if (!rt711->component->card->instantiated) + if (!rt711->component->card || !rt711->component->card->instantiated) return; /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */ @@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711->hs_jack = hs_jack; - if (!rt711->hw_init) { - dev_dbg(&rt711->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt711_sdca_jack_init(rt711); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -1183,19 +1194,16 @@ static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev static int rt711_sdca_probe(struct snd_soc_component *component) { struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; - return 0; -} - -static void rt711_sdca_remove(struct snd_soc_component *component) -{ - struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; - regcache_cache_only(rt711->regmap, true); - regcache_cache_only(rt711->mbq_regmap, true); + return 0; } static const struct snd_soc_component_driver soc_sdca_dev_rt711 = { @@ -1207,7 +1215,7 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = { .dapm_routes = rt711_sdca_audio_map, .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map), .set_jack = rt711_sdca_set_jack_detect, - .remove = rt711_sdca_remove, + .endianness = 1, }; static int rt711_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1358,7 +1366,7 @@ static int rt711_sdca_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt711_sdca_ops = { .hw_params = rt711_sdca_pcm_hw_params, .hw_free = rt711_sdca_pcm_hw_free, - .set_sdw_stream = rt711_sdca_set_sdw_stream, + .set_stream = rt711_sdca_set_sdw_stream, .shutdown = rt711_sdca_shutdown, }; @@ -1411,8 +1419,12 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); + INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_sdca_btn_check_handler); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1544,14 +1556,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00); - if (!rt711->first_hw_init) { - INIT_DELAYED_WORK(&rt711->jack_detect_work, - rt711_sdca_jack_detect_handler); - INIT_DELAYED_WORK(&rt711->jack_btn_check_work, - rt711_sdca_btn_check_handler); - mutex_init(&rt711->calibrate_mutex); - } - /* calibration */ ret = rt711_sdca_calibration(rt711); if (ret < 0) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index bda2cc9439c9..4fe68bcf2a7c 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -13,6 +13,7 @@ #include <linux/soundwire/sdw_type.h> #include <linux/soundwire/sdw_registers.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/soc.h> #include "rt711.h" @@ -464,12 +465,18 @@ static int rt711_sdw_remove(struct sdw_slave *slave) { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); - if (rt711 && rt711->hw_init) { + if (rt711->hw_init) { cancel_delayed_work_sync(&rt711->jack_detect_work); cancel_delayed_work_sync(&rt711->jack_btn_check_work); cancel_work_sync(&rt711->calibration_work); } + if (rt711->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt711->calibrate_mutex); + mutex_destroy(&rt711->disable_irq_lock); + return 0; } diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index a7c5608a0ef8..1bf618089194 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -242,9 +242,16 @@ static void rt711_jack_detect_handler(struct work_struct *work) if (!rt711->hs_jack) return; - if (!rt711->component->card->instantiated) + if (!rt711->component->card || !rt711->component->card->instantiated) return; + if (pm_runtime_status_suspended(rt711->slave->dev.parent)) { + dev_dbg(&rt711->slave->dev, + "%s: parent device is pm_runtime_status_suspended, skipping jack detection\n", + __func__); + return; + } + reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; ret = regmap_read(rt711->regmap, reg, &jack_status); if (ret < 0) @@ -450,17 +457,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *hs_jack, void *data) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711->hs_jack = hs_jack; - if (!rt711->hw_init) { - dev_dbg(&rt711->slave->dev, - "%s hw_init not ready yet\n", __func__); + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); return 0; } rt711_jack_init(rt711); + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -918,18 +935,16 @@ static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) static int rt711_probe(struct snd_soc_component *component) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + int ret; rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; - return 0; -} - -static void rt711_remove(struct snd_soc_component *component) -{ - struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; - regcache_cache_only(rt711->regmap, true); + return 0; } static const struct snd_soc_component_driver soc_codec_dev_rt711 = { @@ -942,7 +957,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = { .dapm_routes = rt711_audio_map, .num_dapm_routes = ARRAY_SIZE(rt711_audio_map), .set_jack = rt711_set_jack_detect, - .remove = rt711_remove, + .endianness = 1, }; static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -1089,7 +1104,7 @@ static int rt711_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt711_ops = { .hw_params = rt711_pcm_hw_params, .hw_free = rt711_pcm_hw_free, - .set_sdw_stream = rt711_set_sdw_stream, + .set_stream = rt711_set_sdw_stream, .shutdown = rt711_shutdown, }; @@ -1196,8 +1211,13 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); + INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler); + INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1305,15 +1325,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->first_hw_init) rt711_calibration(rt711); - else { - INIT_DELAYED_WORK(&rt711->jack_detect_work, - rt711_jack_detect_handler); - INIT_DELAYED_WORK(&rt711->jack_btn_check_work, - rt711_btn_check_handler); - mutex_init(&rt711->calibrate_mutex); - INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + else schedule_work(&rt711->calibration_work); - } /* * if set_jack callback occurred early than io_init, diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index a5c673f43d82..3f981a9e7fb6 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -13,6 +13,7 @@ #include <linux/soundwire/sdw_type.h> #include <linux/soundwire/sdw_registers.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/soc.h> #include "rt715-sdca.h" @@ -181,8 +182,6 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, { struct regmap *mbq_regmap, *regmap; - slave->ops = &rt715_sdca_slave_ops; - /* Regmap Initialization */ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); if (IS_ERR(mbq_regmap)) @@ -195,6 +194,16 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave); } +static int rt715_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); + + if (rt715->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt715_sdca_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0), SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0), @@ -235,6 +244,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } @@ -269,6 +280,7 @@ static struct sdw_driver rt715_sdw_driver = { .pm = &rt715_pm, }, .probe = rt715_sdca_sdw_probe, + .remove = rt715_sdca_sdw_remove, .ops = &rt715_sdca_slave_ops, .id_table = rt715_sdca_id, }; diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 66e166568c50..ce8bbc76199a 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -758,13 +758,26 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { {"ADC 25 Mux", "DMIC4", "DMIC4"}, }; +static int rt715_sdca_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { + .probe = rt715_sdca_probe, .controls = rt715_sdca_snd_controls, .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls), .dapm_widgets = rt715_sdca_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt715_sdca_dapm_widgets), .dapm_routes = rt715_sdca_audio_map, .num_dapm_routes = ARRAY_SIZE(rt715_sdca_audio_map), + .endianness = 1, }; static int rt715_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -938,7 +951,7 @@ static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt715_sdca_ops = { .hw_params = rt715_sdca_pcm_hw_params, .hw_free = rt715_sdca_pcm_hw_free, - .set_sdw_stream = rt715_sdca_set_sdw_stream, + .set_stream = rt715_sdca_set_sdw_stream, .shutdown = rt715_sdca_shutdown, }; diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index a7b21b03c08b..4e61e16470ed 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -14,6 +14,7 @@ #include <linux/soundwire/sdw_type.h> #include <linux/soundwire/sdw_registers.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/regmap.h> #include <sound/soc.h> @@ -514,6 +515,16 @@ static int rt715_sdw_probe(struct sdw_slave *slave, return 0; } +static int rt715_sdw_remove(struct sdw_slave *slave) +{ + struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); + + if (rt715->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + static const struct sdw_device_id rt715_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x2, 0, 0), SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0), @@ -551,6 +562,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } @@ -575,6 +588,7 @@ static struct sdw_driver rt715_sdw_driver = { .pm = &rt715_pm, }, .probe = rt715_sdw_probe, + .remove = rt715_sdw_remove, .ops = &rt715_slave_ops, .id_table = rt715_id, }; diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 1352869cc086..e93240521c74 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -737,7 +737,19 @@ static int rt715_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt715_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rt715 = { + .probe = rt715_probe, .set_bias_level = rt715_set_bias_level, .controls = rt715_snd_controls, .num_controls = ARRAY_SIZE(rt715_snd_controls), @@ -745,6 +757,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt715 = { .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets), .dapm_routes = rt715_audio_map, .num_dapm_routes = ARRAY_SIZE(rt715_audio_map), + .endianness = 1, }; static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -909,7 +922,7 @@ static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt715_ops = { .hw_params = rt715_pcm_hw_params, .hw_free = rt715_pcm_hw_free, - .set_sdw_stream = rt715_set_sdw_stream, + .set_stream = rt715_set_sdw_stream, .shutdown = rt715_shutdown, }; diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index 7aa1772a915f..644300e88b4c 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -7,6 +7,7 @@ #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <sound/pcm.h> @@ -75,6 +76,7 @@ enum { struct rt9120_data { struct device *dev; struct regmap *regmap; + struct gpio_desc *pwdnn_gpio; int chip_idx; }; @@ -160,6 +162,8 @@ static int rt9120_codec_probe(struct snd_soc_component *comp) snd_soc_component_init_regmap(comp, data->regmap); + pm_runtime_get_sync(comp->dev); + /* Internal setting */ if (data->chip_idx == CHIP_IDX_RT9120S) { snd_soc_component_write(comp, RT9120_REG_INTERCFG, 0xde); @@ -167,6 +171,9 @@ static int rt9120_codec_probe(struct snd_soc_component *comp) } else snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x04); + pm_runtime_mark_last_busy(comp->dev); + pm_runtime_put(comp->dev); + return 0; } @@ -178,6 +185,7 @@ static const struct snd_soc_component_driver rt9120_component_driver = { .num_dapm_widgets = ARRAY_SIZE(rt9120_dapm_widgets), .dapm_routes = rt9120_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt9120_dapm_routes), + .endianness = 1, }; static int rt9120_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -337,11 +345,22 @@ static const struct regmap_access_table rt9120_wr_table = { .n_yes_ranges = ARRAY_SIZE(rt9120_wr_yes_ranges), }; +static bool rt9120_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00 ... 0x01: + case 0x10: + case 0x30 ... 0x40: + return true; + default: + return false; + } +} + static int rt9120_get_reg_size(unsigned int reg) { switch (reg) { case 0x00: - case 0x09: case 0x20 ... 0x27: return 2; case 0x30 ... 0x3D: @@ -372,7 +391,7 @@ static int rt9120_reg_read(void *context, unsigned int reg, unsigned int *val) *val = be32_to_cpup((__be32 *)raw); break; case 3: - *val = raw[0] << 16 | raw[1] << 8 | raw[0]; + *val = raw[0] << 16 | raw[1] << 8 | raw[2]; break; case 2: *val = be16_to_cpup((__be16 *)raw); @@ -397,14 +416,49 @@ static int rt9120_reg_write(void *context, unsigned int reg, unsigned int val) return i2c_smbus_write_i2c_block_data(i2c, reg, size, rawp + offs); } +static const struct reg_default rt9120_reg_defaults[] = { + { .reg = 0x02, .def = 0x02 }, + { .reg = 0x03, .def = 0xf2 }, + { .reg = 0x04, .def = 0x01 }, + { .reg = 0x05, .def = 0xc0 }, + { .reg = 0x06, .def = 0x28 }, + { .reg = 0x07, .def = 0x04 }, + { .reg = 0x08, .def = 0xff }, + { .reg = 0x09, .def = 0x01 }, + { .reg = 0x0a, .def = 0x01 }, + { .reg = 0x0b, .def = 0x00 }, + { .reg = 0x0c, .def = 0x04 }, + { .reg = 0x11, .def = 0x30 }, + { .reg = 0x12, .def = 0x08 }, + { .reg = 0x13, .def = 0x12 }, + { .reg = 0x14, .def = 0x09 }, + { .reg = 0x15, .def = 0x00 }, + { .reg = 0x20, .def = 0x7ff }, + { .reg = 0x21, .def = 0x180 }, + { .reg = 0x22, .def = 0x180 }, + { .reg = 0x23, .def = 0x00 }, + { .reg = 0x24, .def = 0x80 }, + { .reg = 0x25, .def = 0x180 }, + { .reg = 0x26, .def = 0x640 }, + { .reg = 0x27, .def = 0x180 }, + { .reg = 0x63, .def = 0x5e }, + { .reg = 0x65, .def = 0x66 }, + { .reg = 0x6c, .def = 0xe0 }, + { .reg = 0xf8, .def = 0x44 }, +}; + static const struct regmap_config rt9120_regmap_config = { .reg_bits = 8, .val_bits = 32, .max_register = RT9120_REG_DIGCFG, + .reg_defaults = rt9120_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt9120_reg_defaults), + .cache_type = REGCACHE_RBTREE, .reg_read = rt9120_reg_read, .reg_write = rt9120_reg_write, + .volatile_reg = rt9120_volatile_reg, .wr_table = &rt9120_wr_table, .rd_table = &rt9120_rd_table, }; @@ -450,7 +504,6 @@ static int rt9120_do_register_reset(struct rt9120_data *data) static int rt9120_probe(struct i2c_client *i2c) { struct rt9120_data *data; - struct gpio_desc *pwdnn_gpio; struct regulator *dvdd_supply; int dvdd_supply_volt, ret; @@ -461,12 +514,12 @@ static int rt9120_probe(struct i2c_client *i2c) data->dev = &i2c->dev; i2c_set_clientdata(i2c, data); - pwdnn_gpio = devm_gpiod_get_optional(&i2c->dev, "pwdnn", - GPIOD_OUT_HIGH); - if (IS_ERR(pwdnn_gpio)) { + data->pwdnn_gpio = devm_gpiod_get_optional(&i2c->dev, "pwdnn", + GPIOD_OUT_HIGH); + if (IS_ERR(data->pwdnn_gpio)) { dev_err(&i2c->dev, "Failed to initialize 'pwdnn' gpio\n"); - return PTR_ERR(pwdnn_gpio); - } else if (pwdnn_gpio) { + return PTR_ERR(data->pwdnn_gpio); + } else if (data->pwdnn_gpio) { dev_dbg(&i2c->dev, "'pwdnn' from low to high, wait chip on\n"); msleep(RT9120_CHIPON_WAITMS); } @@ -508,11 +561,54 @@ static int rt9120_probe(struct i2c_client *i2c) } } + pm_runtime_set_autosuspend_delay(&i2c->dev, 1000); + pm_runtime_use_autosuspend(&i2c->dev); + pm_runtime_set_active(&i2c->dev); + pm_runtime_mark_last_busy(&i2c->dev); + pm_runtime_enable(&i2c->dev); + return devm_snd_soc_register_component(&i2c->dev, &rt9120_component_driver, &rt9120_dai, 1); } +static void rt9120_remove(struct i2c_client *i2c) +{ + pm_runtime_disable(&i2c->dev); + pm_runtime_set_suspended(&i2c->dev); +} + +static int __maybe_unused rt9120_runtime_suspend(struct device *dev) +{ + struct rt9120_data *data = dev_get_drvdata(dev); + + if (data->pwdnn_gpio) { + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + gpiod_set_value(data->pwdnn_gpio, 0); + } + + return 0; +} + +static int __maybe_unused rt9120_runtime_resume(struct device *dev) +{ + struct rt9120_data *data = dev_get_drvdata(dev); + + if (data->pwdnn_gpio) { + gpiod_set_value(data->pwdnn_gpio, 1); + msleep(RT9120_CHIPON_WAITMS); + regcache_cache_only(data->regmap, false); + regcache_sync(data->regmap); + } + + return 0; +} + +static const struct dev_pm_ops rt9120_pm_ops = { + SET_RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL) +}; + static const struct of_device_id __maybe_unused rt9120_device_table[] = { { .compatible = "richtek,rt9120", }, { } @@ -523,8 +619,10 @@ static struct i2c_driver rt9120_driver = { .driver = { .name = "rt9120", .of_match_table = rt9120_device_table, + .pm = &rt9120_pm_ops, }, .probe_new = rt9120_probe, + .remove = rt9120_remove, }; module_i2c_driver(rt9120_driver); diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index 8ea13cfa9f8e..288b55368d2a 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -38,6 +38,7 @@ static void sdw_mockup_component_remove(struct snd_soc_component *component) static const struct snd_soc_component_driver snd_soc_sdw_mockup_component = { .probe = sdw_mockup_component_probe, .remove = sdw_mockup_component_remove, + .endianness = 1, }; static int sdw_mockup_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -138,7 +139,7 @@ static int sdw_mockup_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops sdw_mockup_ops = { .hw_params = sdw_mockup_pcm_hw_params, .hw_free = sdw_mockup_pcm_hw_free, - .set_sdw_stream = sdw_mockup_set_sdw_stream, + .set_stream = sdw_mockup_set_sdw_stream, .shutdown = sdw_mockup_shutdown, }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 97bf1f222805..4b2135eba74d 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1536,7 +1536,6 @@ static const struct snd_soc_component_driver sgtl5000_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sgtl5000_regmap = { @@ -1579,8 +1578,7 @@ static void sgtl5000_fill_defaults(struct i2c_client *client) } } -static int sgtl5000_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sgtl5000_i2c_probe(struct i2c_client *client) { struct sgtl5000_priv *sgtl5000; int ret, reg, rev; @@ -1612,9 +1610,8 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, if (ret == -ENOENT) ret = -EPROBE_DEFER; - if (ret != -EPROBE_DEFER) - dev_err(&client->dev, "Failed to get mclock: %d\n", - ret); + dev_err_probe(&client->dev, ret, "Failed to get mclock\n"); + goto disable_regs; } @@ -1793,15 +1790,21 @@ disable_regs: return ret; } -static int sgtl5000_i2c_remove(struct i2c_client *client) +static void sgtl5000_i2c_remove(struct i2c_client *client) { struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT); + clk_disable_unprepare(sgtl5000->mclk); regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies); regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies); +} - return 0; +static void sgtl5000_i2c_shutdown(struct i2c_client *client) +{ + sgtl5000_i2c_remove(client); } static const struct i2c_device_id sgtl5000_id[] = { @@ -1822,8 +1825,9 @@ static struct i2c_driver sgtl5000_i2c_driver = { .name = "sgtl5000", .of_match_table = sgtl5000_dt_ids, }, - .probe = sgtl5000_i2c_probe, + .probe_new = sgtl5000_i2c_probe, .remove = sgtl5000_i2c_remove, + .shutdown = sgtl5000_i2c_shutdown, .id_table = sgtl5000_id, }; diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 56ec5863f250..3a808c762299 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -80,6 +80,7 @@ /* * SGTL5000_CHIP_DIG_POWER */ +#define SGTL5000_DIG_POWER_DEFAULT 0x0000 #define SGTL5000_ADC_EN 0x0040 #define SGTL5000_DAC_EN 0x0020 #define SGTL5000_DAP_POWERUP 0x0010 diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 8d88db9c11a6..d87141ba8438 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -69,7 +69,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, int err; u16 format = 0; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) return -EINVAL; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -239,7 +239,6 @@ static const struct snd_soc_component_driver soc_component_dev_si476x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int si476x_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index b992216aee55..3047a6fbb380 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -227,13 +227,11 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp, if (!ctrl) return -ENOMEM; - name = kzalloc(name_len + 1, GFP_KERNEL); + name = kmemdup_nul(ctrl_chunk->name, name_len, GFP_KERNEL); if (!name) { ret = -ENOMEM; goto err_free_ctrl; } - memcpy(name, ctrl_chunk->name, name_len); - name[name_len] = '\0'; ctrl->name = name; /* diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c index b30fc1f894e1..d306c585b52b 100644 --- a/sound/soc/codecs/simple-amplifier.c +++ b/sound/soc/codecs/simple-amplifier.c @@ -69,7 +69,6 @@ static int simple_amp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct simple_amp *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (priv == NULL) @@ -78,12 +77,9 @@ static int simple_amp_probe(struct platform_device *pdev) priv->gpiod_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_enable)) { - err = PTR_ERR(priv->gpiod_enable); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'enable' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_enable)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_enable), + "Failed to get 'enable' gpio"); return devm_snd_soc_register_component(dev, &simple_amp_component_driver, diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index e0a09dadfa7c..d30c0d24d90a 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -82,7 +82,6 @@ static int simple_mux_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct simple_mux *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -91,12 +90,9 @@ static int simple_mux_probe(struct platform_device *pdev) dev_set_drvdata(dev, priv); priv->gpiod_mux = devm_gpiod_get(dev, "mux", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_mux)) { - err = PTR_ERR(priv->gpiod_mux); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'mux' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_mux)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux), + "Failed to get 'mux' gpio"); return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0); } diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 276db978e587..862e0b654a1c 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dir = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver dir_stub_dai = { diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index 2c8cebfc6603..736518921555 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dit = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver dit_stub_dai = { diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c new file mode 100644 index 000000000000..43daa9dc8ab5 --- /dev/null +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for SRC4XXX codecs +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt Flax <flatmax@flatmax.com> + +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include "src4xxx.h" + +static int src4xxx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return src4xxx_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL); +} + +static const struct i2c_device_id src4xxx_i2c_ids[] = { + { "src4392", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, src4xxx_i2c_ids); + +static const struct of_device_id src4xxx_of_match[] = { + { .compatible = "ti,src4392", }, + { } +}; +MODULE_DEVICE_TABLE(of, src4xxx_of_match); + + +static struct i2c_driver src4xxx_i2c_driver = { + .driver = { + .name = "src4xxx", + .of_match_table = of_match_ptr(src4xxx_of_match), + }, + .probe = src4xxx_i2c_probe, + .id_table = src4xxx_i2c_ids, +}; +module_i2c_driver(src4xxx_i2c_driver); + +MODULE_DESCRIPTION("ASoC SRC4392 CODEC I2C driver"); +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c new file mode 100644 index 000000000000..db4e280dd055 --- /dev/null +++ b/sound/soc/codecs/src4xxx.c @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TI SRC4xxx Audio Codec driver +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt Flax <flatmax@flatmax.com> + +#include <linux/module.h> + +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "src4xxx.h" + +struct src4xxx { + struct regmap *regmap; + bool master[2]; + int mclk_hz; + struct device *dev; +}; + +enum {SRC4XXX_PORTA, SRC4XXX_PORTB}; + +/* SRC attenuation */ +static const DECLARE_TLV_DB_SCALE(src_tlv, -12750, 50, 0); + +static const struct snd_kcontrol_new src4xxx_controls[] = { + SOC_DOUBLE_R_TLV("SRC Volume", + SRC4XXX_SCR_CTL_30, SRC4XXX_SCR_CTL_31, 0, 255, 1, src_tlv), +}; + +/* I2S port control */ +static const char * const port_out_src_text[] = { + "loopback", "other_port", "DIR", "SRC" +}; +static SOC_ENUM_SINGLE_DECL(porta_out_src_enum, SRC4XXX_PORTA_CTL_03, 4, + port_out_src_text); +static SOC_ENUM_SINGLE_DECL(portb_out_src_enum, SRC4XXX_PORTB_CTL_05, 4, + port_out_src_text); +static const struct snd_kcontrol_new porta_out_control = + SOC_DAPM_ENUM("Port A source select", porta_out_src_enum); +static const struct snd_kcontrol_new portb_out_control = + SOC_DAPM_ENUM("Port B source select", portb_out_src_enum); + +/* Digital audio transmitter control */ +static const char * const dit_mux_text[] = {"Port A", "Port B", "DIR", "SRC"}; +static SOC_ENUM_SINGLE_DECL(dit_mux_enum, SRC4XXX_TX_CTL_07, 3, dit_mux_text); +static const struct snd_kcontrol_new dit_mux_control = + SOC_DAPM_ENUM("DIT source", dit_mux_enum); + +/* SRC control */ +static const char * const src_in_text[] = {"Port A", "Port B", "DIR"}; +static SOC_ENUM_SINGLE_DECL(src_in_enum, SRC4XXX_SCR_CTL_2D, 0, src_in_text); +static const struct snd_kcontrol_new src_in_control = + SOC_DAPM_ENUM("SRC source select", src_in_enum); + +/* DIR control */ +static const char * const dir_in_text[] = {"Ch 1", "Ch 2", "Ch 3", "Ch 4"}; +static SOC_ENUM_SINGLE_DECL(dir_in_enum, SRC4XXX_RCV_CTL_0D, 0, dir_in_text); +static const struct snd_kcontrol_new dir_in_control = + SOC_DAPM_ENUM("Digital Input", dir_in_enum); + +static const struct snd_soc_dapm_widget src4xxx_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("loopback_A"), + SND_SOC_DAPM_INPUT("other_port_A"), + SND_SOC_DAPM_INPUT("DIR_A"), + SND_SOC_DAPM_INPUT("SRC_A"), + SND_SOC_DAPM_MUX("Port A source", + SND_SOC_NOPM, 0, 0, &porta_out_control), + + SND_SOC_DAPM_INPUT("loopback_B"), + SND_SOC_DAPM_INPUT("other_port_B"), + SND_SOC_DAPM_INPUT("DIR_B"), + SND_SOC_DAPM_INPUT("SRC_B"), + SND_SOC_DAPM_MUX("Port B source", + SND_SOC_NOPM, 0, 0, &portb_out_control), + + SND_SOC_DAPM_INPUT("Port_A"), + SND_SOC_DAPM_INPUT("Port_B"), + SND_SOC_DAPM_INPUT("DIR_"), + + /* Digital audio receivers and transmitters */ + SND_SOC_DAPM_OUTPUT("DIR_OUT"), + SND_SOC_DAPM_OUTPUT("SRC_OUT"), + SND_SOC_DAPM_MUX("DIT Out Src", SRC4XXX_PWR_RST_01, + SRC4XXX_ENABLE_DIT_SHIFT, 1, &dit_mux_control), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF_A_RX", "Playback A", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF_A_TX", "Capture A", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1), + SND_SOC_DAPM_AIF_IN("AIF_B_RX", "Playback B", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF_B_TX", "Capture B", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1), + + SND_SOC_DAPM_MUX("SRC source", SND_SOC_NOPM, 0, 0, &src_in_control), + + SND_SOC_DAPM_INPUT("MCLK"), + SND_SOC_DAPM_INPUT("RXMCLKI"), + SND_SOC_DAPM_INPUT("RXMCLKO"), + + SND_SOC_DAPM_INPUT("RX1"), + SND_SOC_DAPM_INPUT("RX2"), + SND_SOC_DAPM_INPUT("RX3"), + SND_SOC_DAPM_INPUT("RX4"), + SND_SOC_DAPM_MUX("Digital Input", SRC4XXX_PWR_RST_01, + SRC4XXX_ENABLE_DIR_SHIFT, 1, &dir_in_control), +}; + +static const struct snd_soc_dapm_route src4xxx_audio_routes[] = { + /* I2S Input to Output Routing */ + {"Port A source", "loopback", "loopback_A"}, + {"Port A source", "other_port", "other_port_A"}, + {"Port A source", "DIR", "DIR_A"}, + {"Port A source", "SRC", "SRC_A"}, + {"Port B source", "loopback", "loopback_B"}, + {"Port B source", "other_port", "other_port_B"}, + {"Port B source", "DIR", "DIR_B"}, + {"Port B source", "SRC", "SRC_B"}, + /* DIT muxing */ + {"DIT Out Src", "Port A", "Capture A"}, + {"DIT Out Src", "Port B", "Capture B"}, + {"DIT Out Src", "DIR", "DIR_OUT"}, + {"DIT Out Src", "SRC", "SRC_OUT"}, + + /* SRC input selection */ + {"SRC source", "Port A", "Port_A"}, + {"SRC source", "Port B", "Port_B"}, + {"SRC source", "DIR", "DIR_"}, + /* SRC mclk selection */ + {"SRC mclk source", "Master (MCLK)", "MCLK"}, + {"SRC mclk source", "Master (RXCLKI)", "RXMCLKI"}, + {"SRC mclk source", "Recovered receiver clk", "RXMCLKO"}, + /* DIR input selection */ + {"Digital Input", "Ch 1", "RX1"}, + {"Digital Input", "Ch 2", "RX2"}, + {"Digital Input", "Ch 3", "RX3"}, + {"Digital Input", "Ch 4", "RX4"}, +}; + + +static const struct snd_soc_component_driver src4xxx_driver = { + .controls = src4xxx_controls, + .num_controls = ARRAY_SIZE(src4xxx_controls), + + .dapm_widgets = src4xxx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(src4xxx_dapm_widgets), + .dapm_routes = src4xxx_audio_routes, + .num_dapm_routes = ARRAY_SIZE(src4xxx_audio_routes), +}; + +static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + unsigned int ctrl; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl = SRC4XXX_BUS_MASTER; + src4xxx->master[dai->id] = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ctrl = 0; + src4xxx->master[dai->id] = false; + break; + default: + return -EINVAL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl |= SRC4XXX_BUS_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl |= SRC4XXX_BUS_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + ctrl |= SRC4XXX_BUS_RIGHT_J_24; + break; + default: + return -EINVAL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + break; + } + + regmap_update_bits(src4xxx->regmap, SRC4XXX_BUS_FMT(dai->id), + SRC4XXX_BUS_FMT_MS_MASK, ctrl); + + return 0; +} + +static int src4xxx_set_mclk_hz(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + + dev_info(component->dev, "changing mclk rate from %d to %d Hz\n", + src4xxx->mclk_hz, freq); + src4xxx->mclk_hz = freq; + + return 0; +} + +static int src4xxx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + unsigned int mclk_div; + int val, pj, jd, d; + int reg; + int ret; + + switch (dai->id) { + case SRC4XXX_PORTB: + reg = SRC4XXX_PORTB_CTL_06; + break; + default: + reg = SRC4XXX_PORTA_CTL_04; + break; + } + + if (src4xxx->master[dai->id]) { + mclk_div = src4xxx->mclk_hz/params_rate(params); + if (src4xxx->mclk_hz != mclk_div*params_rate(params)) { + dev_err(component->dev, + "mclk %d / rate %d has a remainder.\n", + src4xxx->mclk_hz, params_rate(params)); + return -EINVAL; + } + + val = ((int)mclk_div - 128) / 128; + if ((val < 0) | (val > 3)) { + dev_err(component->dev, + "div register setting %d is out of range\n", + val); + dev_err(component->dev, + "unsupported sample rate %d Hz for the master clock of %d Hz\n", + params_rate(params), src4xxx->mclk_hz); + return -EINVAL; + } + + /* set the TX DIV */ + ret = regmap_update_bits(src4xxx->regmap, + SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK, + val<<SRC4XXX_TX_MCLK_DIV_SHIFT); + if (ret) { + dev_err(component->dev, + "Couldn't set the TX's div register to %d << %d = 0x%x\n", + val, SRC4XXX_TX_MCLK_DIV_SHIFT, + val<<SRC4XXX_TX_MCLK_DIV_SHIFT); + return ret; + } + + /* set the PLL for the digital receiver */ + switch (src4xxx->mclk_hz) { + case 24576000: + pj = 0x22; + jd = 0x00; + d = 0x00; + break; + case 22579200: + pj = 0x22; + jd = 0x1b; + d = 0xa3; + break; + default: + /* don't error out here, + * other parts of the chip are still functional + * Dummy initialize variables to avoid + * -Wsometimes-uninitialized from clang. + */ + dev_info(component->dev, + "Couldn't set the RCV PLL as this master clock rate is unknown. Chosen regmap values may not match real world values.\n"); + pj = 0x0; + jd = 0xff; + d = 0xff; + break; + } + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_0F); + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_10, jd); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_10); + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_11, d); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_11); + + ret = regmap_update_bits(src4xxx->regmap, + SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK, + val<<SRC4XXX_TX_MCLK_DIV_SHIFT); + if (ret < 0) { + dev_err(component->dev, + "Couldn't set the TX's div register to %d << %d = 0x%x\n", + val, SRC4XXX_TX_MCLK_DIV_SHIFT, + val<<SRC4XXX_TX_MCLK_DIV_SHIFT); + return ret; + } + + return regmap_update_bits(src4xxx->regmap, reg, + SRC4XXX_MCLK_DIV_MASK, val); + } else { + dev_info(dai->dev, "not setting up MCLK as not master\n"); + } + + return 0; +}; + +static const struct snd_soc_dai_ops src4xxx_dai_ops = { + .hw_params = src4xxx_hw_params, + .set_sysclk = src4xxx_set_mclk_hz, + .set_fmt = src4xxx_set_dai_fmt, +}; + +#define SRC4XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) +#define SRC4XXX_RATES (SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000|\ + SNDRV_PCM_RATE_88200|\ + SNDRV_PCM_RATE_96000|\ + SNDRV_PCM_RATE_176400|\ + SNDRV_PCM_RATE_192000) + +static struct snd_soc_dai_driver src4xxx_dai_driver[] = { + { + .id = SRC4XXX_PORTA, + .name = "src4xxx-portA", + .playback = { + .stream_name = "Playback A", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .capture = { + .stream_name = "Capture A", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .ops = &src4xxx_dai_ops, + }, + { + .id = SRC4XXX_PORTB, + .name = "src4xxx-portB", + .playback = { + .stream_name = "Playback B", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .capture = { + .stream_name = "Capture B", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .ops = &src4xxx_dai_ops, + }, +}; + +static const struct reg_default src4xxx_reg_defaults[] = { + { SRC4XXX_PWR_RST_01, 0x00 }, /* all powered down intially */ + { SRC4XXX_PORTA_CTL_03, 0x00 }, + { SRC4XXX_PORTA_CTL_04, 0x00 }, + { SRC4XXX_PORTB_CTL_05, 0x00 }, + { SRC4XXX_PORTB_CTL_06, 0x00 }, + { SRC4XXX_TX_CTL_07, 0x00 }, + { SRC4XXX_TX_CTL_08, 0x00 }, + { SRC4XXX_TX_CTL_09, 0x00 }, + { SRC4XXX_SRC_DIT_IRQ_MSK_0B, 0x00 }, + { SRC4XXX_SRC_DIT_IRQ_MODE_0C, 0x00 }, + { SRC4XXX_RCV_CTL_0D, 0x00 }, + { SRC4XXX_RCV_CTL_0E, 0x00 }, + { SRC4XXX_RCV_PLL_0F, 0x00 }, /* not spec. in the datasheet */ + { SRC4XXX_RCV_PLL_10, 0xff }, /* not spec. in the datasheet */ + { SRC4XXX_RCV_PLL_11, 0xff }, /* not spec. in the datasheet */ + { SRC4XXX_RVC_IRQ_MSK_16, 0x00 }, + { SRC4XXX_RVC_IRQ_MSK_17, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_18, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_19, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_1A, 0x00 }, + { SRC4XXX_GPIO_1_1B, 0x00 }, + { SRC4XXX_GPIO_2_1C, 0x00 }, + { SRC4XXX_GPIO_3_1D, 0x00 }, + { SRC4XXX_GPIO_4_1E, 0x00 }, + { SRC4XXX_SCR_CTL_2D, 0x00 }, + { SRC4XXX_SCR_CTL_2E, 0x00 }, + { SRC4XXX_SCR_CTL_2F, 0x00 }, + { SRC4XXX_SCR_CTL_30, 0x00 }, + { SRC4XXX_SCR_CTL_31, 0x00 }, +}; + +int src4xxx_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)) +{ + struct src4xxx *src4xxx; + int ret; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + src4xxx = devm_kzalloc(dev, sizeof(*src4xxx), GFP_KERNEL); + if (!src4xxx) + return -ENOMEM; + + src4xxx->regmap = regmap; + src4xxx->dev = dev; + src4xxx->mclk_hz = 0; /* mclk has not been configured yet */ + dev_set_drvdata(dev, src4xxx); + + ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_RESET); + if (ret < 0) + dev_err(dev, "Failed to issue reset: %d\n", ret); + usleep_range(1, 500); /* sleep for more then 500 ns */ + ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_POWER_DOWN); + if (ret < 0) + dev_err(dev, "Failed to decommission reset: %d\n", ret); + usleep_range(500, 1000); /* sleep for 500 us or more */ + + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_PWR_RST_01, + SRC4XXX_POWER_ENABLE, SRC4XXX_POWER_ENABLE); + if (ret < 0) + dev_err(dev, "Failed to port A and B : %d\n", ret); + + /* set receiver to use master clock (rcv mclk is most likely jittery) */ + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0D, + SRC4XXX_RXCLK_MCLK, SRC4XXX_RXCLK_MCLK); + if (ret < 0) + dev_err(dev, + "Failed to enable mclk as the PLL1 DIR reference : %d\n", ret); + + /* default to leaving the PLL2 running on loss of lock, divide by 8 */ + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0E, + SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL, + SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL); + if (ret < 0) + dev_err(dev, "Failed to enable mclk rec and div : %d\n", ret); + + ret = devm_snd_soc_register_component(dev, &src4xxx_driver, + src4xxx_dai_driver, ARRAY_SIZE(src4xxx_dai_driver)); + if (ret == 0) + dev_info(dev, "src4392 probe ok %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(src4xxx_probe); + +static bool src4xxx_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SRC4XXX_RES_00: + case SRC4XXX_GLOBAL_ITR_STS_02: + case SRC4XXX_SRC_DIT_STS_0A: + case SRC4XXX_NON_AUDIO_D_12: + case SRC4XXX_RVC_STS_13: + case SRC4XXX_RVC_STS_14: + case SRC4XXX_RVC_STS_15: + case SRC4XXX_SUB_CODE_1F: + case SRC4XXX_SUB_CODE_20: + case SRC4XXX_SUB_CODE_21: + case SRC4XXX_SUB_CODE_22: + case SRC4XXX_SUB_CODE_23: + case SRC4XXX_SUB_CODE_24: + case SRC4XXX_SUB_CODE_25: + case SRC4XXX_SUB_CODE_26: + case SRC4XXX_SUB_CODE_27: + case SRC4XXX_SUB_CODE_28: + case SRC4XXX_PC_PREAMBLE_HI_29: + case SRC4XXX_PC_PREAMBLE_LO_2A: + case SRC4XXX_PD_PREAMBLE_HI_2B: + case SRC4XXX_PC_PREAMBLE_LO_2C: + case SRC4XXX_IO_RATIO_32: + case SRC4XXX_IO_RATIO_33: + return true; + } + + if (reg > SRC4XXX_IO_RATIO_33 && reg < SRC4XXX_PAGE_SEL_7F) + return true; + + return false; +} + +const struct regmap_config src4xxx_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + .max_register = SRC4XXX_IO_RATIO_33, + + .reg_defaults = src4xxx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(src4xxx_reg_defaults), + .volatile_reg = src4xxx_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(src4xxx_regmap_config); + +MODULE_DESCRIPTION("ASoC SRC4XXX CODEC driver"); +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/src4xxx.h b/sound/soc/codecs/src4xxx.h new file mode 100644 index 000000000000..5bf778fb9945 --- /dev/null +++ b/sound/soc/codecs/src4xxx.h @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// src4xxx.h -- SRC4XXX ALSA SoC audio driver +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt R Flax <flatmax@flatmax.com> + +#ifndef __SRC4XXX_H__ +#define __SRC4XXX_H__ + +#define SRC4XXX_RES_00 0x00 +#define SRC4XXX_PWR_RST_01 0x01 +#define SRC4XXX_RESET 0x80 +#define SRC4XXX_POWER_DOWN 0x00 +#define SRC4XXX_POWER_ENABLE 0x20 +#define SRC4XXX_ENABLE_SRC 0x1 +#define SRC4XXX_ENABLE_SRC_SHIFT 0 +#define SRC4XXX_ENABLE_DIR 0x2 +#define SRC4XXX_ENABLE_DIR_SHIFT 1 +#define SRC4XXX_ENABLE_DIT 0x4 +#define SRC4XXX_ENABLE_DIT_SHIFT 2 +#define SRC4XXX_ENABLE_PORT_B 0x8 +#define SRC4XXX_ENABLE_PORT_B_SHIFT 3 +#define SRC4XXX_ENABLE_PORT_A 0x10 +#define SRC4XXX_ENABLE_PORT_A_SHIFT 4 + +#define SRC4XXX_PORTA_CTL_03 0x03 +#define SRC4XXX_BUS_MASTER 0x8 +#define SRC4XXX_BUS_LEFT_J 0x0 +#define SRC4XXX_BUS_I2S 0x1 +#define SRC4XXX_BUS_RIGHT_J_16 0x4 +#define SRC4XXX_BUS_RIGHT_J_18 0x5 +#define SRC4XXX_BUS_RIGHT_J_20 0x6 +#define SRC4XXX_BUS_RIGHT_J_24 0x7 +#define SRC4XXX_BUS_FMT_MS_MASK 0xf + +#define SRC4XXX_PORTA_CTL_04 0x04 +#define SRC4XXX_MCLK_DIV_MASK 0x3 + +#define SRC4XXX_BUS_FMT(id) (SRC4XXX_PORTA_CTL_03+2*id) +#define SRC4XXX_BUS_CLK(id) (SRC4XXX_PORTA_CTL_04+2*id) + +#define SRC4XXX_PORTB_CTL_05 0x05 +#define SRC4XXX_PORTB_CTL_06 0x06 + +#define SRC4XXX_TX_CTL_07 0x07 +#define SRC4XXX_TX_MCLK_DIV_MASK 0x60 +#define SRC4XXX_TX_MCLK_DIV_SHIFT 5 + +#define SRC4XXX_TX_CTL_08 0x08 +#define SRC4XXX_TX_CTL_09 0x09 +#define SRC4XXX_SRC_DIT_IRQ_MSK_0B 0x0B +#define SRC4XXX_SRC_BTI_EN 0x01 +#define SRC4XXX_SRC_TSLIP_EN 0x02 +#define SRC4XXX_SRC_DIT_IRQ_MODE_0C 0x0C +#define SRC4XXX_RCV_CTL_0D 0x0D +#define SRC4XXX_RXCLK_RXCKI 0x0 +#define SRC4XXX_RXCLK_MCLK 0x8 +#define SRC4XXX_RCV_CTL_0E 0x0E +#define SRC4XXX_REC_MCLK_EN 0x1 +#define SRC4XXX_PLL2_DIV_0 (0x0<<1) +#define SRC4XXX_PLL2_DIV_2 (0x1<<1) +#define SRC4XXX_PLL2_DIV_4 (0x2<<1) +#define SRC4XXX_PLL2_DIV_8 (0x3<<1) +#define SRC4XXX_PLL2_LOL 0x8 +#define SRC4XXX_RCV_PLL_0F 0x0F +#define SRC4XXX_RCV_PLL_10 0x10 +#define SRC4XXX_RCV_PLL_11 0x11 +#define SRC4XXX_RVC_IRQ_MSK_16 0x16 +#define SRC4XXX_RVC_IRQ_MSK_17 0x17 +#define SRC4XXX_RVC_IRQ_MODE_18 0x18 +#define SRC4XXX_RVC_IRQ_MODE_19 0x19 +#define SRC4XXX_RVC_IRQ_MODE_1A 0x1A +#define SRC4XXX_GPIO_1_1B 0x1B +#define SRC4XXX_GPIO_2_1C 0x1C +#define SRC4XXX_GPIO_3_1D 0x1D +#define SRC4XXX_GPIO_4_1E 0x1E +#define SRC4XXX_SCR_CTL_2D 0x2D +#define SRC4XXX_SCR_CTL_2E 0x2E +#define SRC4XXX_SCR_CTL_2F 0x2F +#define SRC4XXX_SCR_CTL_30 0x30 +#define SRC4XXX_SCR_CTL_31 0x31 +#define SRC4XXX_PAGE_SEL_7F 0x7F + +// read only registers +#define SRC4XXX_GLOBAL_ITR_STS_02 0x02 +#define SRC4XXX_SRC_DIT_STS_0A 0x0A +#define SRC4XXX_NON_AUDIO_D_12 0x12 +#define SRC4XXX_RVC_STS_13 0x13 +#define SRC4XXX_RVC_STS_14 0x14 +#define SRC4XXX_RVC_STS_15 0x15 +#define SRC4XXX_SUB_CODE_1F 0x1F +#define SRC4XXX_SUB_CODE_20 0x20 +#define SRC4XXX_SUB_CODE_21 0x21 +#define SRC4XXX_SUB_CODE_22 0x22 +#define SRC4XXX_SUB_CODE_23 0x23 +#define SRC4XXX_SUB_CODE_24 0x24 +#define SRC4XXX_SUB_CODE_25 0x25 +#define SRC4XXX_SUB_CODE_26 0x26 +#define SRC4XXX_SUB_CODE_27 0x27 +#define SRC4XXX_SUB_CODE_28 0x28 +#define SRC4XXX_PC_PREAMBLE_HI_29 0x29 +#define SRC4XXX_PC_PREAMBLE_LO_2A 0x2A +#define SRC4XXX_PD_PREAMBLE_HI_2B 0x2B +#define SRC4XXX_PC_PREAMBLE_LO_2C 0x2C +#define SRC4XXX_IO_RATIO_32 0x32 +#define SRC4XXX_IO_RATIO_33 0x33 + +int src4xxx_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)); +extern const struct regmap_config src4xxx_regmap_config; + +#endif /* __SRC4XXX_H__ */ diff --git a/sound/soc/codecs/ssm2305.c b/sound/soc/codecs/ssm2305.c index 2968959c4b75..1d022643c307 100644 --- a/sound/soc/codecs/ssm2305.c +++ b/sound/soc/codecs/ssm2305.c @@ -57,7 +57,6 @@ static int ssm2305_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ssm2305 *priv; - int err; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -69,13 +68,9 @@ static int ssm2305_probe(struct platform_device *pdev) /* Get shutdown gpio */ priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_shutdown)) { - err = PTR_ERR(priv->gpiod_shutdown); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'shutdown' gpio: %d\n", - err); - return err; - } + if (IS_ERR(priv->gpiod_shutdown)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_shutdown), + "Failed to get 'shutdown' gpio\n"); return devm_snd_soc_register_component(dev, &ssm2305_component_driver, NULL, 0); diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 09449c6c4024..22cb3b7c8283 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -6,14 +6,13 @@ * Author: Lars-Peter Clausen <lars@metafoo.de> */ +#include <linux/err.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> -#include <linux/platform_data/ssm2518.h> +#include <linux/gpio/consumer.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -114,7 +113,7 @@ struct ssm2518 { unsigned int sysclk; const struct snd_pcm_hw_constraint_list *constraints; - int enable_gpio; + struct gpio_desc *enable_gpio; }; static const struct reg_default ssm2518_reg_defaults[] = { @@ -409,8 +408,8 @@ static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) bool invert_fclk; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -483,8 +482,8 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable) regcache_mark_dirty(ssm2518->regmap); } - if (gpio_is_valid(ssm2518->enable_gpio)) - gpio_set_value(ssm2518->enable_gpio, enable); + if (ssm2518->enable_gpio) + gpiod_set_value_cansleep(ssm2518->enable_gpio, enable); regcache_cache_only(ssm2518->regmap, !enable); @@ -721,7 +720,6 @@ static const struct snd_soc_component_driver ssm2518_component_driver = { .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ssm2518_regmap_config = { @@ -735,10 +733,8 @@ static const struct regmap_config ssm2518_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults), }; -static int ssm2518_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ssm2518_i2c_probe(struct i2c_client *i2c) { - struct ssm2518_platform_data *pdata = i2c->dev.platform_data; struct ssm2518 *ssm2518; int ret; @@ -746,22 +742,14 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c, if (ssm2518 == NULL) return -ENOMEM; - if (pdata) { - ssm2518->enable_gpio = pdata->enable_gpio; - } else if (i2c->dev.of_node) { - ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0); - if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT) - return ssm2518->enable_gpio; - } else { - ssm2518->enable_gpio = -1; - } + /* Start with enabling the chip */ + ssm2518->enable_gpio = devm_gpiod_get_optional(&i2c->dev, NULL, + GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(ssm2518->enable_gpio); + if (ret) + return ret; - if (gpio_is_valid(ssm2518->enable_gpio)) { - ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio, - GPIOF_OUT_INIT_HIGH, "SSM2518 nSD"); - if (ret) - return ret; - } + gpiod_set_consumer_name(ssm2518->enable_gpio, "SSM2518 nSD"); i2c_set_clientdata(i2c, ssm2518); @@ -815,7 +803,7 @@ static struct i2c_driver ssm2518_driver = { .name = "ssm2518", .of_match_table = of_match_ptr(ssm2518_dt_ids), }, - .probe = ssm2518_i2c_probe, + .probe_new = ssm2518_i2c_probe, .id_table = ssm2518_i2c_ids, }; module_i2c_driver(ssm2518_driver); diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index afab81383d3a..3c85772901f5 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -13,15 +13,17 @@ #include "ssm2602.h" +static const struct i2c_device_id ssm2602_i2c_id[]; + /* * ssm2602 2 wire address is determined by GPIO5 * state during powerup. * low = 0x1a * high = 0x1b */ -static int ssm2602_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ssm2602_i2c_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_match_id(ssm2602_i2c_id, client); return ssm2602_probe(&client->dev, id->driver_data, devm_regmap_init_i2c(client, &ssm2602_regmap_config)); } @@ -47,7 +49,7 @@ static struct i2c_driver ssm2602_i2c_driver = { .name = "ssm2602", .of_match_table = ssm2602_of_match, }, - .probe = ssm2602_i2c_probe, + .probe_new = ssm2602_i2c_probe, .id_table = ssm2602_i2c_id, }; module_i2c_driver(ssm2602_i2c_driver); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 7964e922b07f..cbbe83b85ada 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -411,11 +411,11 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int iface = 0; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -624,7 +624,6 @@ static const struct snd_soc_component_driver soc_component_dev_ssm2602 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static bool ssm2602_register_volatile(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 811b1a2c404a..4b0265617c7b 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -278,8 +278,8 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl1 = 0; bool invert_fclk; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -427,7 +427,6 @@ static const struct snd_soc_component_driver ssm4567_component_driver = { .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config ssm4567_regmap_config = { @@ -444,8 +443,7 @@ static const struct regmap_config ssm4567_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults), }; -static int ssm4567_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ssm4567_i2c_probe(struct i2c_client *i2c) { struct ssm4567 *ssm4567; int ret; @@ -502,7 +500,7 @@ static struct i2c_driver ssm4567_driver = { .of_match_table = of_match_ptr(ssm4567_of_match), .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, - .probe = ssm4567_i2c_probe, + .probe_new = ssm4567_i2c_probe, .id_table = ssm4567_i2c_ids, }; module_i2c_driver(ssm4567_driver); diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 86528b930de8..8c86b578eba8 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -48,12 +48,9 @@ SNDRV_PCM_RATE_192000) #define STA32X_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) /* Power-up register defaults */ static const struct reg_default sta32x_regs[] = { @@ -604,8 +601,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); u8 confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -1017,7 +1014,6 @@ static const struct snd_soc_component_driver sta32x_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta32x_regmap = { @@ -1094,8 +1090,7 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x) } #endif -static int sta32x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta32x_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct sta32x_priv *sta32x; @@ -1175,7 +1170,7 @@ static struct i2c_driver sta32x_i2c_driver = { .name = "sta32x", .of_match_table = of_match_ptr(st32x_dt_ids), }, - .probe = sta32x_i2c_probe, + .probe_new = sta32x_i2c_probe, .id_table = sta32x_i2c_id, }; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 75d3b0618ab5..9ed13aeb3cbd 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -48,12 +48,9 @@ SNDRV_PCM_RATE_192000) #define STA350_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) /* Power-up register defaults */ static const struct reg_default sta350_regs[] = { @@ -633,8 +630,8 @@ static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component); unsigned int confb = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -1060,7 +1057,6 @@ static const struct snd_soc_component_driver sta350_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta350_regmap = { @@ -1187,8 +1183,7 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) } #endif -static int sta350_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta350_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct sta350_priv *sta350; @@ -1247,10 +1242,8 @@ static int sta350_i2c_probe(struct i2c_client *i2c, return ret; } -static int sta350_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void sta350_i2c_remove(struct i2c_client *client) +{} static const struct i2c_device_id sta350_i2c_id[] = { { "sta350", 0 }, @@ -1263,7 +1256,7 @@ static struct i2c_driver sta350_i2c_driver = { .name = "sta350", .of_match_table = of_match_ptr(st350_dt_ids), }, - .probe = sta350_i2c_probe, + .probe_new = sta350_i2c_probe, .remove = sta350_i2c_remove, .id_table = sta350_i2c_id, }; diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h index f16900e00afa..80bf56093d94 100644 --- a/sound/soc/codecs/sta350.h +++ b/sound/soc/codecs/sta350.h @@ -14,7 +14,7 @@ #ifndef _ASOC_STA_350_H #define _ASOC_STA_350_H -/* STA50 register addresses */ +/* STA350 register addresses */ #define STA350_REGISTER_COUNT 0x4D #define STA350_COEF_COUNT 62 diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 97b5f34027c0..313957099145 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -322,7 +322,6 @@ static const struct snd_soc_component_driver sta529_component_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config sta529_regmap = { @@ -337,8 +336,7 @@ static const struct regmap_config sta529_regmap = { .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; -static int sta529_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int sta529_i2c_probe(struct i2c_client *i2c) { struct sta529 *sta529; int ret; @@ -381,7 +379,7 @@ static struct i2c_driver sta529_i2c_driver = { .name = "sta529", .of_match_table = sta529_of_match, }, - .probe = sta529_i2c_probe, + .probe_new = sta529_i2c_probe, .id_table = sta529_i2c_id, }; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index d99f6e466d0a..1824a71fe053 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -313,8 +313,6 @@ static const struct snd_soc_component_driver soc_component_dev_stac9766 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; static int stac9766_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 82a24e330065..99545bcb2ba9 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -96,11 +96,8 @@ static int sti_sas_write_reg(void *context, unsigned int reg, unsigned int value) { struct sti_sas_data *drvdata = context; - int status; - - status = regmap_write(drvdata->dac.regmap, reg, value); - return status; + return regmap_write(drvdata->dac.regmap, reg, value); } static int sti_sas_init_sas_registers(struct snd_soc_component *component, @@ -154,10 +151,10 @@ static int sti_sas_init_sas_registers(struct snd_soc_component *component, static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { /* Sanity check only */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(dai->component->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + "%s: ERROR: Unsupported clocking 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } @@ -199,10 +196,10 @@ static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(dai->component->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + "%s: ERROR: Unsupported clocking mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } @@ -385,11 +382,8 @@ static int sti_sas_resume(struct snd_soc_component *component) static int sti_sas_component_probe(struct snd_soc_component *component) { struct sti_sas_data *drvdata = dev_get_drvdata(component->dev); - int ret; - ret = sti_sas_init_sas_registers(component, drvdata); - - return ret; + return sti_sas_init_sas_registers(component, drvdata); } static struct snd_soc_component_driver sti_sas_driver = { @@ -398,7 +392,6 @@ static struct snd_soc_component_driver sti_sas_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id sti_sas_dev_match[] = { diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 700baa6314aa..59a4ea5f6e30 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -347,17 +347,17 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct tas2552_data *tas2552 = dev_get_drvdata(component->dev); u8 serial_format; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: serial_format = 0x00; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: serial_format = TAS2552_WCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: serial_format = TAS2552_BCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR); break; default: @@ -581,7 +581,7 @@ static int tas2552_component_probe(struct snd_soc_component *component) gpiod_set_value(tas2552->enable_gpio, 1); - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { dev_err(component->dev, "Enabling device failed: %d\n", ret); @@ -668,7 +668,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2552 = { .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config tas2552_regmap_config = { @@ -681,8 +680,7 @@ static const struct regmap_config tas2552_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int tas2552_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2552_probe(struct i2c_client *client) { struct device *dev; struct tas2552_data *data; @@ -738,10 +736,9 @@ static int tas2552_probe(struct i2c_client *client, return ret; } -static int tas2552_i2c_remove(struct i2c_client *client) +static void tas2552_i2c_remove(struct i2c_client *client) { pm_runtime_disable(&client->dev); - return 0; } static const struct i2c_device_id tas2552_id[] = { @@ -764,7 +761,7 @@ static struct i2c_driver tas2552_i2c_driver = { .of_match_table = of_match_ptr(tas2552_of_match), .pm = &tas2552_pm, }, - .probe = tas2552_probe, + .probe_new = tas2552_probe, .remove = tas2552_i2c_remove, .id_table = tas2552_id, }; diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index 10302552195e..b486d0bd86c9 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -54,6 +54,8 @@ struct tas2562_data { int i_sense_slot; int volume_lvl; int model_id; + bool dac_powered; + bool unmuted; }; enum tas256x_model { @@ -63,39 +65,6 @@ enum tas256x_model { TAS2110, }; -static int tas2562_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct tas2562_data *tas2562 = - snd_soc_component_get_drvdata(component); - - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_SHUTDOWN); - break; - - default: - dev_err(tas2562->dev, - "wrong power level setting %d\n", level); - return -EINVAL; - } - - return 0; -} - static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate) { int samp_rate; @@ -384,30 +353,43 @@ static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int tas2562_update_pwr_ctrl(struct tas2562_data *tas2562) +{ + struct snd_soc_component *component = tas2562->component; + unsigned int val; + int ret; + + if (tas2562->dac_powered) + val = tas2562->unmuted ? + TAS2562_ACTIVE : TAS2562_MUTE; + else + val = TAS2562_SHUTDOWN; + + ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(dai->component); - return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - mute ? TAS2562_MUTE : 0); + tas2562->unmuted = !mute; + return tas2562_update_pwr_ctrl(tas2562); } static int tas2562_codec_probe(struct snd_soc_component *component) { struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); - int ret; tas2562->component = component; if (tas2562->sdz_gpio) gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); - ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_MUTE); - if (ret < 0) - return ret; - return 0; } @@ -457,35 +439,23 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); - int ret; + int ret = 0; switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - TAS2562_MUTE); - if (ret) - goto end; + tas2562->dac_powered = true; + ret = tas2562_update_pwr_ctrl(tas2562); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - TAS2562_SHUTDOWN); - if (ret) - goto end; + tas2562->dac_powered = false; + ret = tas2562_update_pwr_ctrl(tas2562); break; default: dev_err(tas2562->dev, "Not supported evevt\n"); return -EINVAL; } -end: - if (ret < 0) - return ret; - - return 0; + return ret; } static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol, @@ -579,7 +549,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = { .probe = tas2562_codec_probe, .suspend = tas2562_suspend, .resume = tas2562_resume, - .set_bias_level = tas2562_set_bias_level, .controls = tas2562_snd_controls, .num_controls = ARRAY_SIZE(tas2562_snd_controls), .dapm_widgets = tas2110_dapm_widgets, @@ -589,7 +558,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = { @@ -619,7 +587,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = { .probe = tas2562_codec_probe, .suspend = tas2562_suspend, .resume = tas2562_resume, - .set_bias_level = tas2562_set_bias_level, .controls = tas2562_snd_controls, .num_controls = ARRAY_SIZE(tas2562_snd_controls), .dapm_widgets = tas2562_dapm_widgets, @@ -629,7 +596,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = { @@ -754,17 +720,27 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562) return ret; } -static int tas2562_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tas2562_id[] = { + { "tas2562", TAS2562 }, + { "tas2563", TAS2563 }, + { "tas2564", TAS2564 }, + { "tas2110", TAS2110 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2562_id); + +static int tas2562_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas2562_data *data; int ret; + const struct i2c_device_id *id; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + id = i2c_match_id(tas2562_id, client); data->client = client; data->dev = &client->dev; data->model_id = id->driver_data; @@ -792,15 +768,6 @@ static int tas2562_probe(struct i2c_client *client, } -static const struct i2c_device_id tas2562_id[] = { - { "tas2562", TAS2562 }, - { "tas2563", TAS2563 }, - { "tas2564", TAS2564 }, - { "tas2110", TAS2110 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tas2562_id); - #ifdef CONFIG_OF static const struct of_device_id tas2562_of_match[] = { { .compatible = "ti,tas2562", }, @@ -817,7 +784,7 @@ static struct i2c_driver tas2562_i2c_driver = { .name = "tas2562", .of_match_table = of_match_ptr(tas2562_of_match), }, - .probe = tas2562_probe, + .probe_new = tas2562_probe, .id_table = tas2562_id, }; diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 9265af41c235..51b87a936179 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -31,51 +31,96 @@ struct tas2764_priv { struct gpio_desc *sdz_gpio; struct regmap *regmap; struct device *dev; + int irq; int v_sense_slot; int i_sense_slot; + + bool dac_powered; + bool unmuted; +}; + +static const char *tas2764_int_ltch0_msgs[8] = { + "fault: over temperature", /* INT_LTCH0 & BIT(0) */ + "fault: over current", + "fault: bad TDM clock", + "limiter active", + "fault: PVDD below limiter inflection point", + "fault: limiter max attenuation", + "fault: BOP infinite hold", + "fault: BOP mute", /* INT_LTCH0 & BIT(7) */ +}; + +static const unsigned int tas2764_int_readout_regs[6] = { + TAS2764_INT_LTCH0, + TAS2764_INT_LTCH1, + TAS2764_INT_LTCH1_0, + TAS2764_INT_LTCH2, + TAS2764_INT_LTCH3, + TAS2764_INT_LTCH4, }; +static irqreturn_t tas2764_irq(int irq, void *data) +{ + struct tas2764_priv *tas2764 = data; + u8 latched[6] = {0, 0, 0, 0, 0, 0}; + int ret = IRQ_NONE; + int i; + + for (i = 0; i < ARRAY_SIZE(latched); i++) + latched[i] = snd_soc_component_read(tas2764->component, + tas2764_int_readout_regs[i]); + + for (i = 0; i < 8; i++) { + if (latched[0] & BIT(i)) { + dev_crit_ratelimited(tas2764->dev, "%s\n", + tas2764_int_ltch0_msgs[i]); + ret = IRQ_HANDLED; + } + } + + if (latched[0]) { + dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x", + latched[1], latched[2], latched[3], latched[4], latched[5]); + snd_soc_component_update_bits(tas2764->component, + TAS2764_INT_CLK_CFG, + TAS2764_INT_CLK_CFG_IRQZ_CLR, + TAS2764_INT_CLK_CFG_IRQZ_CLR); + } + + return ret; +} + static void tas2764_reset(struct tas2764_priv *tas2764) { if (tas2764->reset_gpio) { gpiod_set_value_cansleep(tas2764->reset_gpio, 0); msleep(20); gpiod_set_value_cansleep(tas2764->reset_gpio, 1); + usleep_range(1000, 2000); } snd_soc_component_write(tas2764->component, TAS2764_SW_RST, TAS2764_RST); + usleep_range(1000, 2000); } -static int tas2764_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) +static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764) { - struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); + struct snd_soc_component *component = tas2764->component; + unsigned int val; + int ret; - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_SHUTDOWN); - break; + if (tas2764->dac_powered) + val = tas2764->unmuted ? + TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE; + else + val = TAS2764_PWR_CTRL_SHUTDOWN; - default: - dev_err(tas2764->dev, - "wrong power level setting %d\n", level); - return -EINVAL; - } + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_MASK, val); + if (ret < 0) + return ret; return 0; } @@ -107,12 +152,12 @@ static int tas2764_codec_resume(struct snd_soc_component *component) struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); int ret; - if (tas2764->sdz_gpio) + if (tas2764->sdz_gpio) { gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); + usleep_range(1000, 2000); + } - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_ACTIVE); + ret = tas2764_update_pwr_ctrl(tas2764); if (ret < 0) return ret; @@ -131,7 +176,8 @@ static const char * const tas2764_ASI1_src[] = { }; static SOC_ENUM_SINGLE_DECL( - tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, 4, tas2764_ASI1_src); + tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT, + tas2764_ASI1_src); static const struct snd_kcontrol_new tas2764_asi1_mux = SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); @@ -145,14 +191,12 @@ static int tas2764_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); + tas2764->dac_powered = true; + ret = tas2764_update_pwr_ctrl(tas2764); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_SHUTDOWN); + tas2764->dac_powered = false; + ret = tas2764_update_pwr_ctrl(tas2764); break; default: dev_err(tas2764->dev, "Unsupported event\n"); @@ -197,17 +241,11 @@ static const struct snd_soc_dapm_route tas2764_audio_map[] = { static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_component *component = dai->component; - int ret; + struct tas2764_priv *tas2764 = + snd_soc_component_get_drvdata(dai->component); - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - mute ? TAS2764_PWR_CTRL_MUTE : 0); - - if (ret < 0) - return ret; - - return 0; + tas2764->unmuted = !mute; + return tas2764_update_pwr_ctrl(tas2764); } static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) @@ -329,20 +367,22 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; - int iface; + u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0; int ret; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_NB_NF: asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING; break; + case SND_SOC_DAIFMT_IB_IF: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_IB_NF: asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING; break; - default: - dev_err(tas2764->dev, "ASI format Inverse is not found\n"); - return -EINVAL; } ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, @@ -353,13 +393,13 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; + fallthrough; case SND_SOC_DAIFMT_DSP_A: - iface = TAS2764_TDM_CFG2_SCFG_I2S; tdm_rx_start_slot = 1; break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_LEFT_J: - iface = TAS2764_TDM_CFG2_SCFG_LEFT_J; tdm_rx_start_slot = 0; break; default: @@ -368,14 +408,15 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, - TAS2764_TDM_CFG1_MASK, - (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT)); + ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0, + TAS2764_TDM_CFG0_FRAME_START, + asi_cfg_0); if (ret < 0) return ret; - ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2, - TAS2764_TDM_CFG2_SCFG_MASK, iface); + ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, + TAS2764_TDM_CFG1_MASK, + (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT)); if (ret < 0) return ret; @@ -477,7 +518,7 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = { .id = 0, .playback = { .stream_name = "ASI1 Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = TAS2764_RATES, .formats = TAS2764_FORMATS, @@ -501,11 +542,41 @@ static int tas2764_codec_probe(struct snd_soc_component *component) tas2764->component = component; - if (tas2764->sdz_gpio) + if (tas2764->sdz_gpio) { gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); + usleep_range(1000, 2000); + } tas2764_reset(tas2764); + if (tas2764->irq) { + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff); + if (ret < 0) + return ret; + + ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, + "tas2764", tas2764); + if (ret) + dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret); + } + ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5, TAS2764_TDM_CFG5_VSNS_ENABLE, 0); if (ret < 0) @@ -516,30 +587,33 @@ static int tas2764_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); - if (ret < 0) - return ret; - return 0; } static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0); -static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10000, 50, 0); +static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1); + +static const char * const tas2764_hpf_texts[] = { + "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz", + "400 Hz", "800 Hz" +}; + +static SOC_ENUM_SINGLE_DECL( + tas2764_hpf_enum, TAS2764_DC_BLK0, + TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts); static const struct snd_kcontrol_new tas2764_snd_controls[] = { SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, TAS2764_DVC_MAX, 1, tas2764_playback_volume), - SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 0, 0x14, 0, + SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, tas2764_digital_tlv), + SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum), }; static const struct snd_soc_component_driver soc_component_driver_tas2764 = { .probe = tas2764_codec_probe, .suspend = tas2764_codec_suspend, .resume = tas2764_codec_resume, - .set_bias_level = tas2764_set_bias_level, .controls = tas2764_snd_controls, .num_controls = ARRAY_SIZE(tas2764_snd_controls), .dapm_widgets = tas2764_dapm_widgets, @@ -548,7 +622,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2764 = { .num_dapm_routes = ARRAY_SIZE(tas2764_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct reg_default tas2764_reg_defaults[] = { @@ -556,7 +629,7 @@ static const struct reg_default tas2764_reg_defaults[] = { { TAS2764_SW_RST, 0x00 }, { TAS2764_PWR_CTRL, 0x1a }, { TAS2764_DVC, 0x00 }, - { TAS2764_CHNL_0, 0x00 }, + { TAS2764_CHNL_0, 0x28 }, { TAS2764_TDM_CFG0, 0x09 }, { TAS2764_TDM_CFG1, 0x02 }, { TAS2764_TDM_CFG2, 0x0a }, @@ -576,9 +649,21 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { }, }; +static bool tas2764_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; + default: + return false; + } +} + static const struct regmap_config tas2764_i2c_regmap = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = tas2764_volatile_register, .reg_defaults = tas2764_reg_defaults, .num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults), .cache_type = REGCACHE_RBTREE, @@ -621,8 +706,7 @@ static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764) return 0; } -static int tas2764_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2764_i2c_probe(struct i2c_client *client) { struct tas2764_priv *tas2764; int result; @@ -633,6 +717,7 @@ static int tas2764_i2c_probe(struct i2c_client *client, return -ENOMEM; tas2764->dev = &client->dev; + tas2764->irq = client->irq; i2c_set_clientdata(client, tas2764); dev_set_drvdata(&client->dev, tas2764); @@ -678,7 +763,7 @@ static struct i2c_driver tas2764_i2c_driver = { .name = "tas2764", .of_match_table = of_match_ptr(tas2764_of_match), }, - .probe = tas2764_i2c_probe, + .probe_new = tas2764_i2c_probe, .id_table = tas2764_i2c_id, }; module_i2c_driver(tas2764_i2c_driver); diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index 67d6fd903c42..168af772a898 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -33,6 +33,10 @@ #define TAS2764_VSENSE_POWER_EN 3 #define TAS2764_ISENSE_POWER_EN 4 +/* DC Blocker Control */ +#define TAS2764_DC_BLK0 TAS2764_REG(0x0, 0x04) +#define TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT 0 + /* Digital Volume Control */ #define TAS2764_DVC TAS2764_REG(0X0, 0x1a) #define TAS2764_DVC_MAX 0xc9 @@ -47,6 +51,7 @@ #define TAS2764_TDM_CFG0_MASK GENMASK(3, 1) #define TAS2764_TDM_CFG0_44_1_48KHZ BIT(3) #define TAS2764_TDM_CFG0_88_2_96KHZ (BIT(3) | BIT(1)) +#define TAS2764_TDM_CFG0_FRAME_START BIT(0) /* TDM Configuration Reg1 */ #define TAS2764_TDM_CFG1 TAS2764_REG(0X0, 0x09) @@ -66,10 +71,7 @@ #define TAS2764_TDM_CFG2_RXS_16BITS 0x0 #define TAS2764_TDM_CFG2_RXS_24BITS BIT(0) #define TAS2764_TDM_CFG2_RXS_32BITS BIT(1) -#define TAS2764_TDM_CFG2_SCFG_MASK GENMASK(5, 4) -#define TAS2764_TDM_CFG2_SCFG_I2S 0x0 -#define TAS2764_TDM_CFG2_SCFG_LEFT_J BIT(4) -#define TAS2764_TDM_CFG2_SCFG_RIGHT_J BIT(5) +#define TAS2764_TDM_CFG2_SCFG_SHIFT 4 /* TDM Configuration Reg3 */ #define TAS2764_TDM_CFG3 TAS2764_REG(0X0, 0x0c) @@ -89,4 +91,23 @@ #define TAS2764_TDM_CFG6_ISNS_ENABLE BIT(6) #define TAS2764_TDM_CFG6_50_MASK GENMASK(5, 0) +/* Interrupt Masks */ +#define TAS2764_INT_MASK0 TAS2764_REG(0x0, 0x3b) +#define TAS2764_INT_MASK1 TAS2764_REG(0x0, 0x3c) +#define TAS2764_INT_MASK2 TAS2764_REG(0x0, 0x40) +#define TAS2764_INT_MASK3 TAS2764_REG(0x0, 0x41) +#define TAS2764_INT_MASK4 TAS2764_REG(0x0, 0x3d) + +/* Latched Fault Registers */ +#define TAS2764_INT_LTCH0 TAS2764_REG(0x0, 0x49) +#define TAS2764_INT_LTCH1 TAS2764_REG(0x0, 0x4a) +#define TAS2764_INT_LTCH1_0 TAS2764_REG(0x0, 0x4b) +#define TAS2764_INT_LTCH2 TAS2764_REG(0x0, 0x4f) +#define TAS2764_INT_LTCH3 TAS2764_REG(0x0, 0x50) +#define TAS2764_INT_LTCH4 TAS2764_REG(0x0, 0x51) + +/* Clock/IRQ Settings */ +#define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c) +#define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2) + #endif /* __TAS2764__ */ diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 172e79cbe0da..b6765235a4b3 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -38,40 +38,30 @@ static void tas2770_reset(struct tas2770_priv *tas2770) gpiod_set_value_cansleep(tas2770->reset_gpio, 0); msleep(20); gpiod_set_value_cansleep(tas2770->reset_gpio, 1); + usleep_range(1000, 2000); } snd_soc_component_write(tas2770->component, TAS2770_SW_RST, TAS2770_RST); + usleep_range(1000, 2000); } -static int tas2770_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) +static int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770) { - struct tas2770_priv *tas2770 = - snd_soc_component_get_drvdata(component); + struct snd_soc_component *component = tas2770->component; + unsigned int val; + int ret; - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_SHUTDOWN); - break; + if (tas2770->dac_powered) + val = tas2770->unmuted ? + TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE; + else + val = TAS2770_PWR_CTRL_SHUTDOWN; - default: - dev_err(tas2770->dev, "wrong power level setting %d\n", level); - return -EINVAL; - } + ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, val); + if (ret < 0) + return ret; return 0; } @@ -110,10 +100,9 @@ static int tas2770_codec_resume(struct snd_soc_component *component) if (tas2770->sdz_gpio) { gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); + usleep_range(1000, 2000); } else { - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); + ret = tas2770_update_pwr_ctrl(tas2770); if (ret < 0) return ret; } @@ -149,24 +138,19 @@ static int tas2770_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); + tas2770->dac_powered = 1; + ret = tas2770_update_pwr_ctrl(tas2770); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_SHUTDOWN); + tas2770->dac_powered = 0; + ret = tas2770_update_pwr_ctrl(tas2770); break; default: dev_err(tas2770->dev, "Not supported evevt\n"); return -EINVAL; } - if (ret < 0) - return ret; - - return 0; + return ret; } static const struct snd_kcontrol_new isense_switch = @@ -200,21 +184,11 @@ static const struct snd_soc_dapm_route tas2770_audio_map[] = { static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction) { struct snd_soc_component *component = dai->component; - int ret; - - if (mute) - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_MUTE); - else - ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, - TAS2770_PWR_CTRL_MASK, - TAS2770_PWR_CTRL_ACTIVE); - - if (ret < 0) - return ret; + struct tas2770_priv *tas2770 = + snd_soc_component_get_drvdata(component); - return 0; + tas2770->unmuted = !mute; + return tas2770_update_pwr_ctrl(tas2770); } static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) @@ -291,11 +265,11 @@ static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate) ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ | TAS2770_TDM_CFG_REG0_31_88_2_96KHZ; break; - case 19200: + case 192000: ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ | TAS2770_TDM_CFG_REG0_31_176_4_192KHZ; break; - case 17640: + case 176400: ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ | TAS2770_TDM_CFG_REG0_31_176_4_192KHZ; break; @@ -334,21 +308,27 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); - u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(tas2770->dev, "ASI format master is not found\n"); + dev_err(tas2770->dev, "ASI invalid DAI clocking\n"); return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + invert_fpol = 1; + fallthrough; case SND_SOC_DAIFMT_NB_NF: asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING; break; + case SND_SOC_DAIFMT_IB_IF: + invert_fpol = 1; + fallthrough; case SND_SOC_DAIFMT_IB_NF: asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING; break; @@ -366,15 +346,19 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: tdm_rx_start_slot = 1; + fpol_preinv = 0; break; case SND_SOC_DAIFMT_DSP_A: tdm_rx_start_slot = 0; + fpol_preinv = 1; break; case SND_SOC_DAIFMT_DSP_B: tdm_rx_start_slot = 1; + fpol_preinv = 1; break; case SND_SOC_DAIFMT_LEFT_J: tdm_rx_start_slot = 0; + fpol_preinv = 1; break; default: dev_err(tas2770->dev, @@ -388,6 +372,14 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (ret < 0) return ret; + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0, + TAS2770_TDM_CFG_REG0_FPOL_MASK, + (fpol_preinv ^ invert_fpol) + ? TAS2770_TDM_CFG_REG0_FPOL_RSING + : TAS2770_TDM_CFG_REG0_FPOL_FALING); + if (ret < 0) + return ret; + return 0; } @@ -486,7 +478,7 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = { .id = 0, .playback = { .stream_name = "ASI1 Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = TAS2770_RATES, .formats = TAS2770_FORMATS, @@ -503,6 +495,8 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = { }, }; +static const struct regmap_config tas2770_i2c_regmap; + static int tas2770_codec_probe(struct snd_soc_component *component) { struct tas2770_priv *tas2770 = @@ -510,10 +504,13 @@ static int tas2770_codec_probe(struct snd_soc_component *component) tas2770->component = component; - if (tas2770->sdz_gpio) + if (tas2770->sdz_gpio) { gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); + usleep_range(1000, 2000); + } tas2770_reset(tas2770); + regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap); return 0; } @@ -532,7 +529,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = { .probe = tas2770_codec_probe, .suspend = tas2770_codec_suspend, .resume = tas2770_codec_resume, - .set_bias_level = tas2770_set_bias_level, .controls = tas2770_snd_controls, .num_controls = ARRAY_SIZE(tas2770_snd_controls), .dapm_widgets = tas2770_dapm_widgets, @@ -541,7 +537,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = { .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map), .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int tas2770_register_codec(struct tas2770_priv *tas2770) @@ -667,8 +662,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) return 0; } -static int tas2770_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas2770_i2c_probe(struct i2c_client *client) { struct tas2770_priv *tas2770; int result; @@ -734,7 +728,7 @@ static struct i2c_driver tas2770_i2c_driver = { .name = "tas2770", .of_match_table = of_match_ptr(tas2770_of_match), }, - .probe = tas2770_i2c_probe, + .probe_new = tas2770_i2c_probe, .id_table = tas2770_i2c_id, }; module_i2c_driver(tas2770_i2c_driver); diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h index d156666bcc55..f75f40781ab1 100644 --- a/sound/soc/codecs/tas2770.h +++ b/sound/soc/codecs/tas2770.h @@ -41,6 +41,9 @@ #define TAS2770_TDM_CFG_REG0_31_44_1_48KHZ 0x6 #define TAS2770_TDM_CFG_REG0_31_88_2_96KHZ 0x8 #define TAS2770_TDM_CFG_REG0_31_176_4_192KHZ 0xa +#define TAS2770_TDM_CFG_REG0_FPOL_MASK BIT(0) +#define TAS2770_TDM_CFG_REG0_FPOL_RSING 0 +#define TAS2770_TDM_CFG_REG0_FPOL_FALING 1 /* TDM Configuration Reg1 */ #define TAS2770_TDM_CFG_REG1 TAS2770_REG(0X0, 0x0B) #define TAS2770_TDM_CFG_REG1_MASK GENMASK(5, 1) @@ -135,6 +138,8 @@ struct tas2770_priv { struct device *dev; int v_sense_slot; int i_sense_slot; + bool dac_powered; + bool unmuted; }; #endif /* __TAS2770__ */ diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c new file mode 100644 index 000000000000..a6db6f0e5431 --- /dev/null +++ b/sound/soc/codecs/tas2780.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0 +// Driver for the Texas Instruments TAS2780 Mono +// Audio amplifier +// Copyright (C) 2022 Texas Instruments Inc. + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#include "tas2780.h" + +struct tas2780_priv { + struct snd_soc_component *component; + struct gpio_desc *reset_gpio; + struct regmap *regmap; + struct device *dev; + int v_sense_slot; + int i_sense_slot; +}; + +static void tas2780_reset(struct tas2780_priv *tas2780) +{ + int ret = 0; + + if (tas2780->reset_gpio) { + gpiod_set_value_cansleep(tas2780->reset_gpio, 0); + usleep_range(2000, 2050); + gpiod_set_value_cansleep(tas2780->reset_gpio, 1); + usleep_range(2000, 2050); + } + + snd_soc_component_write(tas2780->component, TAS2780_SW_RST, + TAS2780_RST); + if (ret) + dev_err(tas2780->dev, "%s:errCode:0x%x Reset error!\n", + __func__, ret); +} + +#ifdef CONFIG_PM +static int tas2780_codec_suspend(struct snd_soc_component *component) +{ + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int ret = 0; + + ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, + TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_SHUTDOWN); + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n", + __func__, ret); + goto err; + } + ret = 0; + regcache_cache_only(tas2780->regmap, true); + regcache_mark_dirty(tas2780->regmap); +err: + return ret; +} + +static int tas2780_codec_resume(struct snd_soc_component *component) +{ + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int ret = 0; + + ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, + TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_ACTIVE); + + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n", + __func__, ret); + goto err; + } + ret = 0; + regcache_cache_only(tas2780->regmap, false); + ret = regcache_sync(tas2780->regmap); +err: + return ret; +} +#endif + +static const char * const tas2780_ASI1_src[] = { + "I2C offset", "Left", "Right", "LeftRightDiv2", +}; + +static SOC_ENUM_SINGLE_DECL( + tas2780_ASI1_src_enum, TAS2780_TDM_CFG2, 4, tas2780_ASI1_src); + +static const struct snd_kcontrol_new tas2780_asi1_mux = + SOC_DAPM_ENUM("ASI1 Source", tas2780_ASI1_src_enum); + +static const struct snd_kcontrol_new isense_switch = + SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL, + TAS2780_ISENSE_POWER_EN, 1, 1); +static const struct snd_kcontrol_new vsense_switch = + SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL, + TAS2780_VSENSE_POWER_EN, 1, 1); + +static const struct snd_soc_dapm_widget tas2780_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2780_asi1_mux), + SND_SOC_DAPM_SWITCH("ISENSE", TAS2780_PWR_CTRL, + TAS2780_ISENSE_POWER_EN, 1, &isense_switch), + SND_SOC_DAPM_SWITCH("VSENSE", TAS2780_PWR_CTRL, + TAS2780_VSENSE_POWER_EN, 1, &vsense_switch), + SND_SOC_DAPM_OUTPUT("OUT"), + SND_SOC_DAPM_SIGGEN("VMON"), + SND_SOC_DAPM_SIGGEN("IMON") +}; + +static const struct snd_soc_dapm_route tas2780_audio_map[] = { + {"ASI1 Sel", "I2C offset", "ASI1"}, + {"ASI1 Sel", "Left", "ASI1"}, + {"ASI1 Sel", "Right", "ASI1"}, + {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, + {"OUT", NULL, "ASI1 Sel"}, + {"ISENSE", "Switch", "IMON"}, + {"VSENSE", "Switch", "VMON"}, +}; + +static int tas2780_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int ret = 0; + + ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, + TAS2780_PWR_CTRL_MASK, + mute ? TAS2780_PWR_CTRL_MUTE : 0); + if (ret < 0) { + dev_err(tas2780->dev, "%s: Failed to set powercontrol\n", + __func__); + goto err; + } + ret = 0; +err: + return ret; +} + +static int tas2780_set_bitwidth(struct tas2780_priv *tas2780, int bitwidth) +{ + struct snd_soc_component *component = tas2780->component; + int sense_en; + int val; + int ret; + int slot_size; + + switch (bitwidth) { + case SNDRV_PCM_FORMAT_S16_LE: + ret = snd_soc_component_update_bits(component, + TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_RXW_MASK, + TAS2780_TDM_CFG2_RXW_16BITS); + slot_size = TAS2780_TDM_CFG2_RXS_16BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ret = snd_soc_component_update_bits(component, + TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_RXW_MASK, + TAS2780_TDM_CFG2_RXW_24BITS); + slot_size = TAS2780_TDM_CFG2_RXS_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + ret = snd_soc_component_update_bits(component, + TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_RXW_MASK, + TAS2780_TDM_CFG2_RXW_32BITS); + slot_size = TAS2780_TDM_CFG2_RXS_32BITS; + break; + + default: + ret = -EINVAL; + } + + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%x set bitwidth error\n", + __func__, ret); + goto err; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_RXS_MASK, slot_size); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x set RX slot size error\n", + __func__, ret); + goto err; + } + + val = snd_soc_component_read(tas2780->component, TAS2780_PWR_CTRL); + if (val < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%x read PWR_CTRL error\n", + __func__, val); + ret = val; + goto err; + } + + if (val & (1 << TAS2780_VSENSE_POWER_EN)) + sense_en = 0; + else + sense_en = TAS2780_TDM_CFG5_VSNS_ENABLE; + + ret = snd_soc_component_update_bits(tas2780->component, + TAS2780_TDM_CFG5, TAS2780_TDM_CFG5_VSNS_ENABLE, sense_en); + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%x enable vSNS error\n", + __func__, ret); + goto err; + } + + if (val & (1 << TAS2780_ISENSE_POWER_EN)) + sense_en = 0; + else + sense_en = TAS2780_TDM_CFG6_ISNS_ENABLE; + + ret = snd_soc_component_update_bits(tas2780->component, + TAS2780_TDM_CFG6, TAS2780_TDM_CFG6_ISNS_ENABLE, sense_en); + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%x enable iSNS error\n", + __func__, ret); + goto err; + } + ret = 0; +err: + return ret; +} + +static int tas2780_set_samplerate( + struct tas2780_priv *tas2780, int samplerate) +{ + struct snd_soc_component *component = tas2780->component; + int ramp_rate_val; + int ret; + + switch (samplerate) { + case 48000: + ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ | + TAS2780_TDM_CFG0_44_1_48KHZ; + break; + case 44100: + ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ | + TAS2780_TDM_CFG0_44_1_48KHZ; + break; + case 96000: + ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ | + TAS2780_TDM_CFG0_88_2_96KHZ; + break; + case 88200: + ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ | + TAS2780_TDM_CFG0_88_2_96KHZ; + break; + default: + return -EINVAL; + } + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG0, + TAS2780_TDM_CFG0_SMP_MASK | TAS2780_TDM_CFG0_MASK, + ramp_rate_val); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set ramp_rate_val\n", + __func__, ret); + goto err; + } + ret = 0; +err: + return ret; +} + +static int tas2780_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int ret; + + ret = tas2780_set_bitwidth(tas2780, params_format(params)); + if (ret < 0) + return ret; + + return tas2780_set_samplerate(tas2780, params_rate(params)); +} + +static int tas2780_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; + int iface; + int ret = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + asi_cfg_1 = TAS2780_TDM_CFG1_RX_RISING; + break; + case SND_SOC_DAIFMT_IB_NF: + asi_cfg_1 = TAS2780_TDM_CFG1_RX_FALLING; + break; + default: + dev_err(tas2780->dev, "ASI format Inverse is not found\n"); + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1, + TAS2780_TDM_CFG1_RX_MASK, asi_cfg_1); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set asi_cfg_1\n", + __func__, ret); + goto err; + } + + if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) + || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_DSP_A)){ + iface = TAS2780_TDM_CFG2_SCFG_I2S; + tdm_rx_start_slot = 1; + } else { + if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_DSP_B) + || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_LEFT_J)) { + iface = TAS2780_TDM_CFG2_SCFG_LEFT_J; + tdm_rx_start_slot = 0; + } else { + dev_err(tas2780->dev, + "%s:DAI Format is not found, fmt=0x%x\n", + __func__, fmt); + ret = -EINVAL; + goto err; + } + } + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1, + TAS2780_TDM_CFG1_MASK, + (tdm_rx_start_slot << TAS2780_TDM_CFG1_51_SHIFT)); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set tdm_rx_start_slot\n", + __func__, ret); + goto err; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_SCFG_MASK, iface); + if (ret < 0) { + dev_err(tas2780->dev, "%s:errCode:0x%x Failed to set iface\n", + __func__, ret); + goto err; + } + ret = 0; +err: + return ret; +} + +static int tas2780_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int left_slot, right_slot; + int slots_cfg; + int slot_size; + int ret = 0; + + if (tx_mask == 0 || rx_mask != 0) + return -EINVAL; + + if (slots == 1) { + if (tx_mask != 1) + return -EINVAL; + left_slot = 0; + right_slot = 0; + } else { + left_slot = __ffs(tx_mask); + tx_mask &= ~(1 << left_slot); + if (tx_mask == 0) { + right_slot = left_slot; + } else { + right_slot = __ffs(tx_mask); + tx_mask &= ~(1 << right_slot); + } + } + + if (tx_mask != 0 || left_slot >= slots || right_slot >= slots) + return -EINVAL; + + slots_cfg = (right_slot << TAS2780_TDM_CFG3_RXS_SHIFT) | left_slot; + ret = snd_soc_component_write(component, TAS2780_TDM_CFG3, slots_cfg); + if (ret) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set slots_cfg\n", + __func__, ret); + goto err; + } + + switch (slot_width) { + case 16: + slot_size = TAS2780_TDM_CFG2_RXS_16BITS; + break; + case 24: + slot_size = TAS2780_TDM_CFG2_RXS_24BITS; + break; + case 32: + slot_size = TAS2780_TDM_CFG2_RXS_32BITS; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, + TAS2780_TDM_CFG2_RXS_MASK, slot_size); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set slot_size\n", + __func__, ret); + goto err; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG5, + TAS2780_TDM_CFG5_50_MASK, tas2780->v_sense_slot); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set v_sense_slot\n", + __func__, ret); + goto err; + } + + ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG6, + TAS2780_TDM_CFG6_50_MASK, tas2780->i_sense_slot); + if (ret < 0) { + dev_err(tas2780->dev, + "%s:errCode:0x%x Failed to set i_sense_slot\n", + __func__, ret); + goto err; + } + ret = 0; +err: + return ret; +} + +static const struct snd_soc_dai_ops tas2780_dai_ops = { + .mute_stream = tas2780_mute, + .hw_params = tas2780_hw_params, + .set_fmt = tas2780_set_fmt, + .set_tdm_slot = tas2780_set_dai_tdm_slot, + .no_capture_mute = 1, +}; + +#define TAS2780_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define TAS2780_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200) + +static struct snd_soc_dai_driver tas2780_dai_driver[] = { + { + .name = "tas2780 ASI1", + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TAS2780_RATES, + .formats = TAS2780_FORMATS, + }, + .capture = { + .stream_name = "ASI1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = TAS2780_RATES, + .formats = TAS2780_FORMATS, + }, + .ops = &tas2780_dai_ops, + .symmetric_rate = 1, + }, +}; + +static int tas2780_codec_probe(struct snd_soc_component *component) +{ + struct tas2780_priv *tas2780 = + snd_soc_component_get_drvdata(component); + int ret = 0; + + tas2780->component = component; + + tas2780_reset(tas2780); + ret = snd_soc_component_update_bits(component, + TAS2780_IC_CFG, TAS2780_IC_CFG_MASK, + TAS2780_IC_CFG_ENABLE); + if (ret < 0) + dev_err(tas2780->dev, "%s:errCode:0x%0x\n", + __func__, ret); + + return ret; +} + +static DECLARE_TLV_DB_SCALE(tas2780_digital_tlv, 1100, 50, 0); +static DECLARE_TLV_DB_SCALE(tas2780_playback_volume, -10000, 50, 0); + +static const struct snd_kcontrol_new tas2780_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", TAS2780_DVC, 0, + TAS2780_DVC_MAX, 1, tas2780_playback_volume), + SOC_SINGLE_TLV("Amp Gain Volume", TAS2780_CHNL_0, 0, 0x14, 0, + tas2780_digital_tlv), +}; + +static const struct snd_soc_component_driver soc_component_driver_tas2780 = { + .probe = tas2780_codec_probe, +#ifdef CONFIG_PM + .suspend = tas2780_codec_suspend, + .resume = tas2780_codec_resume, +#endif + .controls = tas2780_snd_controls, + .num_controls = ARRAY_SIZE(tas2780_snd_controls), + .dapm_widgets = tas2780_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2780_dapm_widgets), + .dapm_routes = tas2780_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2780_audio_map), + .idle_bias_on = 1, + .endianness = 1, +}; + +static const struct reg_default tas2780_reg_defaults[] = { + { TAS2780_PAGE, 0x00 }, + { TAS2780_SW_RST, 0x00 }, + { TAS2780_PWR_CTRL, 0x1a }, + { TAS2780_DVC, 0x00 }, + { TAS2780_CHNL_0, 0x00 }, + { TAS2780_TDM_CFG0, 0x09 }, + { TAS2780_TDM_CFG1, 0x02 }, + { TAS2780_TDM_CFG2, 0x0a }, + { TAS2780_TDM_CFG3, 0x10 }, + { TAS2780_TDM_CFG5, 0x42 }, +}; + +static const struct regmap_range_cfg tas2780_regmap_ranges[] = { + { + .range_min = 0, + .range_max = 1 * 128, + .selector_reg = TAS2780_PAGE, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 128, + }, +}; + +static const struct regmap_config tas2780_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .reg_defaults = tas2780_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas2780_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .ranges = tas2780_regmap_ranges, + .num_ranges = ARRAY_SIZE(tas2780_regmap_ranges), + .max_register = 1 * 128, +}; + +static int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780) +{ + int ret = 0; + + tas2780->reset_gpio = devm_gpiod_get_optional(tas2780->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(tas2780->reset_gpio)) { + if (PTR_ERR(tas2780->reset_gpio) == -EPROBE_DEFER) { + tas2780->reset_gpio = NULL; + return -EPROBE_DEFER; + } + } + + ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", + &tas2780->i_sense_slot); + if (ret) + tas2780->i_sense_slot = 0; + + ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", + &tas2780->v_sense_slot); + if (ret) + tas2780->v_sense_slot = 2; + + return 0; +} + +static int tas2780_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tas2780_priv *tas2780; + int result; + + tas2780 = devm_kzalloc(&client->dev, sizeof(struct tas2780_priv), + GFP_KERNEL); + if (!tas2780) + return -ENOMEM; + tas2780->dev = &client->dev; + i2c_set_clientdata(client, tas2780); + dev_set_drvdata(&client->dev, tas2780); + + tas2780->regmap = devm_regmap_init_i2c(client, &tas2780_i2c_regmap); + if (IS_ERR(tas2780->regmap)) { + result = PTR_ERR(tas2780->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + result); + return result; + } + + if (client->dev.of_node) { + result = tas2780_parse_dt(&client->dev, tas2780); + if (result) { + dev_err(tas2780->dev, + "%s: Failed to parse devicetree\n", __func__); + return result; + } + } + + return devm_snd_soc_register_component(tas2780->dev, + &soc_component_driver_tas2780, tas2780_dai_driver, + ARRAY_SIZE(tas2780_dai_driver)); +} + +static const struct i2c_device_id tas2780_i2c_id[] = { + { "tas2780", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas2780_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id tas2780_of_match[] = { + { .compatible = "ti,tas2780" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tas2780_of_match); +#endif + +static struct i2c_driver tas2780_i2c_driver = { + .driver = { + .name = "tas2780", + .of_match_table = of_match_ptr(tas2780_of_match), + }, + .probe = tas2780_i2c_probe, + .id_table = tas2780_i2c_id, +}; +module_i2c_driver(tas2780_i2c_driver); + +MODULE_AUTHOR("Raphael Xu <raphael-xu@ti.com>"); +MODULE_DESCRIPTION("TAS2780 I2C Smart Amplifier driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas2780.h b/sound/soc/codecs/tas2780.h new file mode 100644 index 000000000000..661c25df4e29 --- /dev/null +++ b/sound/soc/codecs/tas2780.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * TAS2780.h - ALSA SoC Texas Instruments TAS2780 Mono Audio Amplifier + * + * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com + * + * Author: Raphael Xu <raphael-xu@ti.com> + */ + +#ifndef __TAS2780_H__ +#define __TAS2780_H__ + +/* Book Control Register */ +#define TAS2780_BOOKCTL_PAGE 0 +#define TAS2780_BOOKCTL_REG 127 +#define TAS2780_REG(page, reg) ((page * 128) + reg) + +/* Page */ +#define TAS2780_PAGE TAS2780_REG(0X0, 0x00) +#define TAS2780_PAGE_PAGE_MASK 255 + +/* Software Reset */ +#define TAS2780_SW_RST TAS2780_REG(0X0, 0x01) +#define TAS2780_RST BIT(0) + +/* Power Control */ +#define TAS2780_PWR_CTRL TAS2780_REG(0X0, 0x02) +#define TAS2780_PWR_CTRL_MASK GENMASK(1, 0) +#define TAS2780_PWR_CTRL_ACTIVE 0x0 +#define TAS2780_PWR_CTRL_MUTE BIT(0) +#define TAS2780_PWR_CTRL_SHUTDOWN BIT(1) + +#define TAS2780_VSENSE_POWER_EN 3 +#define TAS2780_ISENSE_POWER_EN 4 + +/* Digital Volume Control */ +#define TAS2780_DVC TAS2780_REG(0X0, 0x1a) +#define TAS2780_DVC_MAX 0xc9 + +#define TAS2780_CHNL_0 TAS2780_REG(0X0, 0x03) + +/* TDM Configuration Reg0 */ +#define TAS2780_TDM_CFG0 TAS2780_REG(0X0, 0x08) +#define TAS2780_TDM_CFG0_SMP_MASK BIT(5) +#define TAS2780_TDM_CFG0_SMP_48KHZ 0x0 +#define TAS2780_TDM_CFG0_SMP_44_1KHZ BIT(5) +#define TAS2780_TDM_CFG0_MASK GENMASK(3, 1) +#define TAS2780_TDM_CFG0_44_1_48KHZ BIT(3) +#define TAS2780_TDM_CFG0_88_2_96KHZ (BIT(3) | BIT(1)) + +/* TDM Configuration Reg1 */ +#define TAS2780_TDM_CFG1 TAS2780_REG(0X0, 0x09) +#define TAS2780_TDM_CFG1_MASK GENMASK(5, 1) +#define TAS2780_TDM_CFG1_51_SHIFT 1 +#define TAS2780_TDM_CFG1_RX_MASK BIT(0) +#define TAS2780_TDM_CFG1_RX_RISING 0x0 +#define TAS2780_TDM_CFG1_RX_FALLING BIT(0) + +/* TDM Configuration Reg2 */ +#define TAS2780_TDM_CFG2 TAS2780_REG(0X0, 0x0a) +#define TAS2780_TDM_CFG2_RXW_MASK GENMASK(3, 2) +#define TAS2780_TDM_CFG2_RXW_16BITS 0x0 +#define TAS2780_TDM_CFG2_RXW_24BITS BIT(3) +#define TAS2780_TDM_CFG2_RXW_32BITS (BIT(3) | BIT(2)) +#define TAS2780_TDM_CFG2_RXS_MASK GENMASK(1, 0) +#define TAS2780_TDM_CFG2_RXS_16BITS 0x0 +#define TAS2780_TDM_CFG2_RXS_24BITS BIT(0) +#define TAS2780_TDM_CFG2_RXS_32BITS BIT(1) +#define TAS2780_TDM_CFG2_SCFG_MASK GENMASK(5, 4) +#define TAS2780_TDM_CFG2_SCFG_I2S 0x0 +#define TAS2780_TDM_CFG2_SCFG_LEFT_J BIT(4) +#define TAS2780_TDM_CFG2_SCFG_RIGHT_J BIT(5) + +/* TDM Configuration Reg3 */ +#define TAS2780_TDM_CFG3 TAS2780_REG(0X0, 0x0c) +#define TAS2780_TDM_CFG3_RXS_MASK GENMASK(7, 4) +#define TAS2780_TDM_CFG3_RXS_SHIFT 0x4 +#define TAS2780_TDM_CFG3_MASK GENMASK(3, 0) + +/* TDM Configuration Reg4 */ +#define TAS2780_TDM_CFG4 TAS2780_REG(0X0, 0x0d) +#define TAS2780_TDM_CFG4_TX_OFFSET_MASK GENMASK(3, 1) + +/* TDM Configuration Reg5 */ +#define TAS2780_TDM_CFG5 TAS2780_REG(0X0, 0x0e) +#define TAS2780_TDM_CFG5_VSNS_MASK BIT(6) +#define TAS2780_TDM_CFG5_VSNS_ENABLE BIT(6) +#define TAS2780_TDM_CFG5_50_MASK GENMASK(5, 0) + +/* TDM Configuration Reg6 */ +#define TAS2780_TDM_CFG6 TAS2780_REG(0X0, 0x0f) +#define TAS2780_TDM_CFG6_ISNS_MASK BIT(6) +#define TAS2780_TDM_CFG6_ISNS_ENABLE BIT(6) +#define TAS2780_TDM_CFG6_50_MASK GENMASK(5, 0) + +/* IC CFG */ +#define TAS2780_IC_CFG TAS2780_REG(0X0, 0x5c) +#define TAS2780_IC_CFG_MASK GENMASK(7, 6) +#define TAS2780_IC_CFG_ENABLE (BIT(7) | BIT(6)) + +#endif /* __TAS2780_H__ */ diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 7831c96d0d83..22143cc5afa7 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -318,7 +318,7 @@ static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, struct tas5086_private *priv = snd_soc_component_get_drvdata(component); /* The TAS5086 can only be slave to all clocks */ - if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { dev_err(component->dev, "Invalid clocking mode\n"); return -EINVAL; } @@ -888,7 +888,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5086 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct i2c_device_id tas5086_i2c_id[] = { @@ -911,8 +910,7 @@ static const struct regmap_config tas5086_regmap = { .reg_write = tas5086_reg_write, }; -static int tas5086_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tas5086_i2c_probe(struct i2c_client *i2c) { struct tas5086_private *priv; struct device *dev = &i2c->dev; @@ -983,10 +981,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, return ret; } -static int tas5086_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} +static void tas5086_i2c_remove(struct i2c_client *i2c) +{} static struct i2c_driver tas5086_i2c_driver = { .driver = { @@ -994,7 +990,7 @@ static struct i2c_driver tas5086_i2c_driver = { .of_match_table = of_match_ptr(tas5086_dt_ids), }, .id_table = tas5086_i2c_id, - .probe = tas5086_i2c_probe, + .probe_new = tas5086_i2c_probe, .remove = tas5086_i2c_remove, }; diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index a3e682376946..84ec1b527646 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -756,7 +756,6 @@ static const struct snd_soc_component_driver tas571x_component = { .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver tas571x_dai = { @@ -774,9 +773,9 @@ static struct snd_soc_dai_driver tas571x_dai = { }; static const struct of_device_id tas571x_of_match[] __maybe_unused; +static const struct i2c_device_id tas571x_i2c_id[]; -static int tas571x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas571x_i2c_probe(struct i2c_client *client) { struct tas571x_private *priv; struct device *dev = &client->dev; @@ -791,8 +790,11 @@ static int tas571x_i2c_probe(struct i2c_client *client, of_id = of_match_device(tas571x_of_match, dev); if (of_id) priv->chip = of_id->data; - else + else { + const struct i2c_device_id *id = + i2c_match_id(tas571x_i2c_id, client); priv->chip = (void *) id->driver_data; + } priv->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { @@ -830,7 +832,8 @@ static int tas571x_i2c_probe(struct i2c_client *client, if (IS_ERR(priv->pdn_gpio)) { dev_err(dev, "error requesting pdn_gpio: %ld\n", PTR_ERR(priv->pdn_gpio)); - return PTR_ERR(priv->pdn_gpio); + ret = PTR_ERR(priv->pdn_gpio); + goto disable_regs; } priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", @@ -838,7 +841,8 @@ static int tas571x_i2c_probe(struct i2c_client *client, if (IS_ERR(priv->reset_gpio)) { dev_err(dev, "error requesting reset_gpio: %ld\n", PTR_ERR(priv->reset_gpio)); - return PTR_ERR(priv->reset_gpio); + ret = PTR_ERR(priv->reset_gpio); + goto disable_regs; } else if (priv->reset_gpio) { /* pulse the active low reset line for ~100us */ usleep_range(100, 200); @@ -880,13 +884,11 @@ disable_regs: return ret; } -static int tas571x_i2c_remove(struct i2c_client *client) +static void tas571x_i2c_remove(struct i2c_client *client) { struct tas571x_private *priv = i2c_get_clientdata(client); regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies); - - return 0; } static const struct of_device_id tas571x_of_match[] __maybe_unused = { @@ -914,7 +916,7 @@ static struct i2c_driver tas571x_i2c_driver = { .name = "tas571x", .of_match_table = of_match_ptr(tas571x_of_match), }, - .probe = tas571x_i2c_probe, + .probe_new = tas571x_i2c_probe, .remove = tas571x_i2c_remove, .id_table = tas571x_i2c_id, }; diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 9ff644ddb470..3885c0bf0b01 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -89,8 +89,8 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) u8 serial_format; int ret; - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - dev_vdbg(component->dev, "DAI Format master is not found\n"); + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { + dev_vdbg(component->dev, "DAI clocking invalid\n"); return -EINVAL; } @@ -572,7 +572,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_component_driver soc_component_dev_tas5722 = { @@ -589,7 +588,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5722 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* PCM rates supported by the TAS5720 driver */ @@ -633,12 +631,19 @@ static struct snd_soc_dai_driver tas5720_dai[] = { }, }; -static int tas5720_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tas5720_id[] = { + { "tas5720", TAS5720 }, + { "tas5722", TAS5722 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas5720_id); + +static int tas5720_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas5720_data *data; const struct regmap_config *regmap_config; + const struct i2c_device_id *id; int ret; int i; @@ -646,6 +651,7 @@ static int tas5720_probe(struct i2c_client *client, if (!data) return -ENOMEM; + id = i2c_match_id(tas5720_id, client); data->tas5720_client = client; data->devtype = id->driver_data; @@ -704,13 +710,6 @@ static int tas5720_probe(struct i2c_client *client, return 0; } -static const struct i2c_device_id tas5720_id[] = { - { "tas5720", TAS5720 }, - { "tas5722", TAS5722 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tas5720_id); - #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tas5720_of_match[] = { { .compatible = "ti,tas5720", }, @@ -725,7 +724,7 @@ static struct i2c_driver tas5720_i2c_driver = { .name = "tas5720", .of_match_table = of_match_ptr(tas5720_of_match), }, - .probe = tas5720_probe, + .probe_new = tas5720_probe, .id_table = tas5720_id, }; diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c new file mode 100644 index 000000000000..beb4ec629a03 --- /dev/null +++ b/sound/soc/codecs/tas5805m.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for the TAS5805M Audio Amplifier +// +// Author: Andy Liu <andy-liu@ti.com> +// Author: Daniel Beer <daniel.beer@igorinstitute.com> +// +// This is based on a driver originally written by Andy Liu at TI and +// posted here: +// +// https://e2e.ti.com/support/audio-group/audio/f/audio-forum/722027/linux-tas5825m-linux-drivers +// +// It has been simplified a little and reworked for the 5.x ALSA SoC API. + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> +#include <linux/atomic.h> +#include <linux/workqueue.h> + +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/initval.h> + +/* Datasheet-defined registers on page 0, book 0 */ +#define REG_PAGE 0x00 +#define REG_DEVICE_CTRL_1 0x02 +#define REG_DEVICE_CTRL_2 0x03 +#define REG_SIG_CH_CTRL 0x28 +#define REG_SAP_CTRL_1 0x33 +#define REG_FS_MON 0x37 +#define REG_BCK_MON 0x38 +#define REG_CLKDET_STATUS 0x39 +#define REG_VOL_CTL 0x4c +#define REG_AGAIN 0x54 +#define REG_ADR_PIN_CTRL 0x60 +#define REG_ADR_PIN_CONFIG 0x61 +#define REG_CHAN_FAULT 0x70 +#define REG_GLOBAL_FAULT1 0x71 +#define REG_GLOBAL_FAULT2 0x72 +#define REG_FAULT 0x78 +#define REG_BOOK 0x7f + +/* DEVICE_CTRL_2 register values */ +#define DCTRL2_MODE_DEEP_SLEEP 0x00 +#define DCTRL2_MODE_SLEEP 0x01 +#define DCTRL2_MODE_HIZ 0x02 +#define DCTRL2_MODE_PLAY 0x03 + +#define DCTRL2_MUTE 0x08 +#define DCTRL2_DIS_DSP 0x10 + +/* This sequence of register writes must always be sent, prior to the + * 5ms delay while we wait for the DSP to boot. + */ +static const uint8_t dsp_cfg_preboot[] = { + 0x00, 0x00, 0x7f, 0x00, 0x03, 0x02, 0x01, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x00, 0x03, 0x02, +}; + +static const uint32_t tas5805m_volume[] = { + 0x0000001B, /* 0, -110dB */ 0x0000001E, /* 1, -109dB */ + 0x00000021, /* 2, -108dB */ 0x00000025, /* 3, -107dB */ + 0x0000002A, /* 4, -106dB */ 0x0000002F, /* 5, -105dB */ + 0x00000035, /* 6, -104dB */ 0x0000003B, /* 7, -103dB */ + 0x00000043, /* 8, -102dB */ 0x0000004B, /* 9, -101dB */ + 0x00000054, /* 10, -100dB */ 0x0000005E, /* 11, -99dB */ + 0x0000006A, /* 12, -98dB */ 0x00000076, /* 13, -97dB */ + 0x00000085, /* 14, -96dB */ 0x00000095, /* 15, -95dB */ + 0x000000A7, /* 16, -94dB */ 0x000000BC, /* 17, -93dB */ + 0x000000D3, /* 18, -92dB */ 0x000000EC, /* 19, -91dB */ + 0x00000109, /* 20, -90dB */ 0x0000012A, /* 21, -89dB */ + 0x0000014E, /* 22, -88dB */ 0x00000177, /* 23, -87dB */ + 0x000001A4, /* 24, -86dB */ 0x000001D8, /* 25, -85dB */ + 0x00000211, /* 26, -84dB */ 0x00000252, /* 27, -83dB */ + 0x0000029A, /* 28, -82dB */ 0x000002EC, /* 29, -81dB */ + 0x00000347, /* 30, -80dB */ 0x000003AD, /* 31, -79dB */ + 0x00000420, /* 32, -78dB */ 0x000004A1, /* 33, -77dB */ + 0x00000532, /* 34, -76dB */ 0x000005D4, /* 35, -75dB */ + 0x0000068A, /* 36, -74dB */ 0x00000756, /* 37, -73dB */ + 0x0000083B, /* 38, -72dB */ 0x0000093C, /* 39, -71dB */ + 0x00000A5D, /* 40, -70dB */ 0x00000BA0, /* 41, -69dB */ + 0x00000D0C, /* 42, -68dB */ 0x00000EA3, /* 43, -67dB */ + 0x0000106C, /* 44, -66dB */ 0x0000126D, /* 45, -65dB */ + 0x000014AD, /* 46, -64dB */ 0x00001733, /* 47, -63dB */ + 0x00001A07, /* 48, -62dB */ 0x00001D34, /* 49, -61dB */ + 0x000020C5, /* 50, -60dB */ 0x000024C4, /* 51, -59dB */ + 0x00002941, /* 52, -58dB */ 0x00002E49, /* 53, -57dB */ + 0x000033EF, /* 54, -56dB */ 0x00003A45, /* 55, -55dB */ + 0x00004161, /* 56, -54dB */ 0x0000495C, /* 57, -53dB */ + 0x0000524F, /* 58, -52dB */ 0x00005C5A, /* 59, -51dB */ + 0x0000679F, /* 60, -50dB */ 0x00007444, /* 61, -49dB */ + 0x00008274, /* 62, -48dB */ 0x0000925F, /* 63, -47dB */ + 0x0000A43B, /* 64, -46dB */ 0x0000B845, /* 65, -45dB */ + 0x0000CEC1, /* 66, -44dB */ 0x0000E7FB, /* 67, -43dB */ + 0x00010449, /* 68, -42dB */ 0x0001240C, /* 69, -41dB */ + 0x000147AE, /* 70, -40dB */ 0x00016FAA, /* 71, -39dB */ + 0x00019C86, /* 72, -38dB */ 0x0001CEDC, /* 73, -37dB */ + 0x00020756, /* 74, -36dB */ 0x000246B5, /* 75, -35dB */ + 0x00028DCF, /* 76, -34dB */ 0x0002DD96, /* 77, -33dB */ + 0x00033718, /* 78, -32dB */ 0x00039B87, /* 79, -31dB */ + 0x00040C37, /* 80, -30dB */ 0x00048AA7, /* 81, -29dB */ + 0x00051884, /* 82, -28dB */ 0x0005B7B1, /* 83, -27dB */ + 0x00066A4A, /* 84, -26dB */ 0x000732AE, /* 85, -25dB */ + 0x00081385, /* 86, -24dB */ 0x00090FCC, /* 87, -23dB */ + 0x000A2ADB, /* 88, -22dB */ 0x000B6873, /* 89, -21dB */ + 0x000CCCCD, /* 90, -20dB */ 0x000E5CA1, /* 91, -19dB */ + 0x00101D3F, /* 92, -18dB */ 0x0012149A, /* 93, -17dB */ + 0x00144961, /* 94, -16dB */ 0x0016C311, /* 95, -15dB */ + 0x00198A13, /* 96, -14dB */ 0x001CA7D7, /* 97, -13dB */ + 0x002026F3, /* 98, -12dB */ 0x00241347, /* 99, -11dB */ + 0x00287A27, /* 100, -10dB */ 0x002D6A86, /* 101, -9dB */ + 0x0032F52D, /* 102, -8dB */ 0x00392CEE, /* 103, -7dB */ + 0x004026E7, /* 104, -6dB */ 0x0047FACD, /* 105, -5dB */ + 0x0050C336, /* 106, -4dB */ 0x005A9DF8, /* 107, -3dB */ + 0x0065AC8C, /* 108, -2dB */ 0x00721483, /* 109, -1dB */ + 0x00800000, /* 110, 0dB */ 0x008F9E4D, /* 111, 1dB */ + 0x00A12478, /* 112, 2dB */ 0x00B4CE08, /* 113, 3dB */ + 0x00CADDC8, /* 114, 4dB */ 0x00E39EA9, /* 115, 5dB */ + 0x00FF64C1, /* 116, 6dB */ 0x011E8E6A, /* 117, 7dB */ + 0x0141857F, /* 118, 8dB */ 0x0168C0C6, /* 119, 9dB */ + 0x0194C584, /* 120, 10dB */ 0x01C62940, /* 121, 11dB */ + 0x01FD93C2, /* 122, 12dB */ 0x023BC148, /* 123, 13dB */ + 0x02818508, /* 124, 14dB */ 0x02CFCC01, /* 125, 15dB */ + 0x0327A01A, /* 126, 16dB */ 0x038A2BAD, /* 127, 17dB */ + 0x03F8BD7A, /* 128, 18dB */ 0x0474CD1B, /* 129, 19dB */ + 0x05000000, /* 130, 20dB */ 0x059C2F02, /* 131, 21dB */ + 0x064B6CAE, /* 132, 22dB */ 0x07100C4D, /* 133, 23dB */ + 0x07ECA9CD, /* 134, 24dB */ 0x08E43299, /* 135, 25dB */ + 0x09F9EF8E, /* 136, 26dB */ 0x0B319025, /* 137, 27dB */ + 0x0C8F36F2, /* 138, 28dB */ 0x0E1787B8, /* 139, 29dB */ + 0x0FCFB725, /* 140, 30dB */ 0x11BD9C84, /* 141, 31dB */ + 0x13E7C594, /* 142, 32dB */ 0x16558CCB, /* 143, 33dB */ + 0x190F3254, /* 144, 34dB */ 0x1C1DF80E, /* 145, 35dB */ + 0x1F8C4107, /* 146, 36dB */ 0x2365B4BF, /* 147, 37dB */ + 0x27B766C2, /* 148, 38dB */ 0x2C900313, /* 149, 39dB */ + 0x32000000, /* 150, 40dB */ 0x3819D612, /* 151, 41dB */ + 0x3EF23ECA, /* 152, 42dB */ 0x46A07B07, /* 153, 43dB */ + 0x4F3EA203, /* 154, 44dB */ 0x58E9F9F9, /* 155, 45dB */ + 0x63C35B8E, /* 156, 46dB */ 0x6FEFA16D, /* 157, 47dB */ + 0x7D982575, /* 158, 48dB */ +}; + +#define TAS5805M_VOLUME_MAX ((int)ARRAY_SIZE(tas5805m_volume) - 1) +#define TAS5805M_VOLUME_MIN 0 + +struct tas5805m_priv { + struct regulator *pvdd; + struct gpio_desc *gpio_pdn_n; + + uint8_t *dsp_cfg_data; + int dsp_cfg_len; + + struct regmap *regmap; + + int vol[2]; + bool is_powered; + bool is_muted; +}; + +static void set_dsp_scale(struct regmap *rm, int offset, int vol) +{ + uint8_t v[4]; + uint32_t x = tas5805m_volume[vol]; + int i; + + for (i = 0; i < 4; i++) { + v[3 - i] = x; + x >>= 8; + } + + regmap_bulk_write(rm, offset, v, ARRAY_SIZE(v)); +} + +static void tas5805m_refresh(struct snd_soc_component *component) +{ + struct tas5805m_priv *tas5805m = + snd_soc_component_get_drvdata(component); + struct regmap *rm = tas5805m->regmap; + + dev_dbg(component->dev, "refresh: is_muted=%d, vol=%d/%d\n", + tas5805m->is_muted, tas5805m->vol[0], tas5805m->vol[1]); + + regmap_write(rm, REG_PAGE, 0x00); + regmap_write(rm, REG_BOOK, 0x8c); + regmap_write(rm, REG_PAGE, 0x2a); + + /* Refresh volume. The actual volume control documented in the + * datasheet doesn't seem to work correctly. This is a pair of + * DSP registers which are *not* documented in the datasheet. + */ + set_dsp_scale(rm, 0x24, tas5805m->vol[0]); + set_dsp_scale(rm, 0x28, tas5805m->vol[1]); + + /* Set/clear digital soft-mute */ + regmap_write(rm, REG_DEVICE_CTRL_2, + (tas5805m->is_muted ? DCTRL2_MUTE : 0) | + DCTRL2_MODE_PLAY); +} + +static int tas5805m_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + + uinfo->value.integer.min = TAS5805M_VOLUME_MIN; + uinfo->value.integer.max = TAS5805M_VOLUME_MAX; + return 0; +} + +static int tas5805m_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tas5805m_priv *tas5805m = + snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = tas5805m->vol[0]; + ucontrol->value.integer.value[1] = tas5805m->vol[1]; + return 0; +} + +static inline int volume_is_valid(int v) +{ + return (v >= TAS5805M_VOLUME_MIN) && (v <= TAS5805M_VOLUME_MAX); +} + +static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct tas5805m_priv *tas5805m = + snd_soc_component_get_drvdata(component); + + if (!(volume_is_valid(ucontrol->value.integer.value[0]) && + volume_is_valid(ucontrol->value.integer.value[1]))) + return -EINVAL; + + if (tas5805m->vol[0] != ucontrol->value.integer.value[0] || + tas5805m->vol[1] != ucontrol->value.integer.value[1]) { + tas5805m->vol[0] = ucontrol->value.integer.value[0]; + tas5805m->vol[1] = ucontrol->value.integer.value[1]; + dev_dbg(component->dev, "set vol=%d/%d (is_powered=%d)\n", + tas5805m->vol[0], tas5805m->vol[1], + tas5805m->is_powered); + if (tas5805m->is_powered) + tas5805m_refresh(component); + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new tas5805m_snd_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = tas5805m_vol_info, + .get = tas5805m_vol_get, + .put = tas5805m_vol_put, + }, +}; + +static void send_cfg(struct regmap *rm, + const uint8_t *s, unsigned int len) +{ + unsigned int i; + + for (i = 0; i + 1 < len; i += 2) + regmap_write(rm, s[i], s[i + 1]); +} + +/* The TAS5805M DSP can't be configured until the I2S clock has been + * present and stable for 5ms, or else it won't boot and we get no + * sound. + */ +static int tas5805m_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct tas5805m_priv *tas5805m = + snd_soc_component_get_drvdata(component); + struct regmap *rm = tas5805m->regmap; + unsigned int chan, global1, global2; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dev_dbg(component->dev, "DSP startup\n"); + + /* We mustn't issue any I2C transactions until the I2S + * clock is stable. Furthermore, we must allow a 5ms + * delay after the first set of register writes to + * allow the DSP to boot before configuring it. + */ + usleep_range(5000, 10000); + send_cfg(rm, dsp_cfg_preboot, + ARRAY_SIZE(dsp_cfg_preboot)); + usleep_range(5000, 15000); + send_cfg(rm, tas5805m->dsp_cfg_data, + tas5805m->dsp_cfg_len); + + tas5805m->is_powered = true; + tas5805m_refresh(component); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dev_dbg(component->dev, "DSP shutdown\n"); + + tas5805m->is_powered = false; + + regmap_write(rm, REG_PAGE, 0x00); + regmap_write(rm, REG_BOOK, 0x00); + + regmap_read(rm, REG_CHAN_FAULT, &chan); + regmap_read(rm, REG_GLOBAL_FAULT1, &global1); + regmap_read(rm, REG_GLOBAL_FAULT2, &global2); + + dev_dbg(component->dev, + "fault regs: CHAN=%02x, GLOBAL1=%02x, GLOBAL2=%02x\n", + chan, global1, global2); + + regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_route tas5805m_audio_map[] = { + { "DAC", NULL, "DAC IN" }, + { "OUT", NULL, "DAC" }, +}; + +static const struct snd_soc_dapm_widget tas5805m_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUT") +}; + +static const struct snd_soc_component_driver soc_codec_dev_tas5805m = { + .controls = tas5805m_snd_controls, + .num_controls = ARRAY_SIZE(tas5805m_snd_controls), + .dapm_widgets = tas5805m_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas5805m_dapm_widgets), + .dapm_routes = tas5805m_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas5805m_audio_map), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct tas5805m_priv *tas5805m = + snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n", + mute, tas5805m->is_powered); + tas5805m->is_muted = mute; + if (tas5805m->is_powered) + tas5805m_refresh(component); + + return 0; +} + +static const struct snd_soc_dai_ops tas5805m_dai_ops = { + .trigger = tas5805m_trigger, + .mute_stream = tas5805m_mute, + .no_capture_mute = 1, +}; + +static struct snd_soc_dai_driver tas5805m_dai = { + .name = "tas5805m-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tas5805m_dai_ops, +}; + +static const struct regmap_config tas5805m_regmap = { + .reg_bits = 8, + .val_bits = 8, + + /* We have quite a lot of multi-level bank switching and a + * relatively small number of register writes between bank + * switches. + */ + .cache_type = REGCACHE_NONE, +}; + +static int tas5805m_i2c_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct regmap *regmap; + struct tas5805m_priv *tas5805m; + char filename[128]; + const char *config_name; + const struct firmware *fw; + int ret; + + regmap = devm_regmap_init_i2c(i2c, &tas5805m_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "unable to allocate register map: %d\n", ret); + return ret; + } + + tas5805m = devm_kzalloc(dev, sizeof(struct tas5805m_priv), GFP_KERNEL); + if (!tas5805m) + return -ENOMEM; + + tas5805m->pvdd = devm_regulator_get(dev, "pvdd"); + if (IS_ERR(tas5805m->pvdd)) { + dev_err(dev, "failed to get pvdd supply: %ld\n", + PTR_ERR(tas5805m->pvdd)); + return PTR_ERR(tas5805m->pvdd); + } + + dev_set_drvdata(dev, tas5805m); + tas5805m->regmap = regmap; + tas5805m->gpio_pdn_n = devm_gpiod_get(dev, "pdn", GPIOD_OUT_LOW); + if (IS_ERR(tas5805m->gpio_pdn_n)) { + dev_err(dev, "error requesting PDN gpio: %ld\n", + PTR_ERR(tas5805m->gpio_pdn_n)); + return PTR_ERR(tas5805m->gpio_pdn_n); + } + + /* This configuration must be generated by PPC3. The file loaded + * consists of a sequence of register writes, where bytes at + * even indices are register addresses and those at odd indices + * are register values. + * + * The fixed portion of PPC3's output prior to the 5ms delay + * should be omitted. + */ + if (device_property_read_string(dev, "ti,dsp-config-name", + &config_name)) + config_name = "default"; + + snprintf(filename, sizeof(filename), "tas5805m_dsp_%s.bin", + config_name); + ret = request_firmware(&fw, filename, dev); + if (ret) + return ret; + + if ((fw->size < 2) || (fw->size & 1)) { + dev_err(dev, "firmware is invalid\n"); + release_firmware(fw); + return -EINVAL; + } + + tas5805m->dsp_cfg_len = fw->size; + tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL); + if (!tas5805m->dsp_cfg_data) { + release_firmware(fw); + return -ENOMEM; + } + memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size); + + release_firmware(fw); + + /* Do the first part of the power-on here, while we can expect + * the I2S interface to be quiet. We must raise PDN# and then + * wait 5ms before any I2S clock is sent, or else the internal + * regulator apparently won't come on. + * + * Also, we must keep the device in power down for 100ms or so + * after PVDD is applied, or else the ADR pin is sampled + * incorrectly and the device comes up with an unpredictable I2C + * address. + */ + tas5805m->vol[0] = TAS5805M_VOLUME_MIN; + tas5805m->vol[1] = TAS5805M_VOLUME_MIN; + + ret = regulator_enable(tas5805m->pvdd); + if (ret < 0) { + dev_err(dev, "failed to enable pvdd: %d\n", ret); + return ret; + } + + usleep_range(100000, 150000); + gpiod_set_value(tas5805m->gpio_pdn_n, 1); + usleep_range(10000, 15000); + + /* Don't register through devm. We need to be able to unregister + * the component prior to deasserting PDN# + */ + ret = snd_soc_register_component(dev, &soc_codec_dev_tas5805m, + &tas5805m_dai, 1); + if (ret < 0) { + dev_err(dev, "unable to register codec: %d\n", ret); + gpiod_set_value(tas5805m->gpio_pdn_n, 0); + regulator_disable(tas5805m->pvdd); + return ret; + } + + return 0; +} + +static void tas5805m_i2c_remove(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct tas5805m_priv *tas5805m = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + gpiod_set_value(tas5805m->gpio_pdn_n, 0); + usleep_range(10000, 15000); + regulator_disable(tas5805m->pvdd); +} + +static const struct i2c_device_id tas5805m_i2c_id[] = { + { "tas5805m", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas5805m_i2c_id); + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id tas5805m_of_match[] = { + { .compatible = "ti,tas5805m", }, + { } +}; +MODULE_DEVICE_TABLE(of, tas5805m_of_match); +#endif + +static struct i2c_driver tas5805m_i2c_driver = { + .probe_new = tas5805m_i2c_probe, + .remove = tas5805m_i2c_remove, + .id_table = tas5805m_i2c_id, + .driver = { + .name = "tas5805m", + .of_match_table = of_match_ptr(tas5805m_of_match), + }, +}; + +module_i2c_driver(tas5805m_i2c_driver); + +MODULE_AUTHOR("Andy Liu <andy-liu@ti.com>"); +MODULE_AUTHOR("Daniel Beer <daniel.beer@igorinstitute.com>"); +MODULE_DESCRIPTION("TAS5805M Audio Amplifier Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 59543d392110..f8ff69fa2549 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -160,11 +160,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt); /* clock masters */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clocking\n"); return -EINVAL; } @@ -375,7 +375,6 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { .num_dapm_routes = ARRAY_SIZE(tas6424_audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { @@ -682,8 +681,7 @@ static const struct of_device_id tas6424_of_ids[] = { MODULE_DEVICE_TABLE(of, tas6424_of_ids); #endif -static int tas6424_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tas6424_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tas6424_data *tas6424; @@ -757,7 +755,7 @@ static int tas6424_i2c_probe(struct i2c_client *client, TAS6424_RESET, TAS6424_RESET); if (ret) { dev_err(dev, "unable to reset device: %d\n", ret); - return ret; + goto disable_regs; } INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work); @@ -766,13 +764,17 @@ static int tas6424_i2c_probe(struct i2c_client *client, tas6424_dai, ARRAY_SIZE(tas6424_dai)); if (ret < 0) { dev_err(dev, "unable to register codec: %d\n", ret); - return ret; + goto disable_regs; } return 0; + +disable_regs: + regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), tas6424->supplies); + return ret; } -static int tas6424_i2c_remove(struct i2c_client *client) +static void tas6424_i2c_remove(struct i2c_client *client) { struct device *dev = &client->dev; struct tas6424_data *tas6424 = dev_get_drvdata(dev); @@ -786,12 +788,8 @@ static int tas6424_i2c_remove(struct i2c_client *client) ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), tas6424->supplies); - if (ret < 0) { + if (ret < 0) dev_err(dev, "unable to disable supplies: %d\n", ret); - return ret; - } - - return 0; } static const struct i2c_device_id tas6424_i2c_ids[] = { @@ -805,7 +803,7 @@ static struct i2c_driver tas6424_i2c_driver = { .name = "tas6424", .of_match_table = of_match_ptr(tas6424_of_ids), }, - .probe = tas6424_i2c_probe, + .probe_new = tas6424_i2c_probe, .remove = tas6424_i2c_remove, .id_table = tas6424_i2c_ids, }; diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c index 83d220054c96..d964e5207569 100644 --- a/sound/soc/codecs/tda7419.c +++ b/sound/soc/codecs/tda7419.c @@ -571,8 +571,7 @@ static const struct snd_soc_component_driver tda7419_component_driver = { .num_dapm_routes = ARRAY_SIZE(tda7419_dapm_routes), }; -static int tda7419_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tda7419_probe(struct i2c_client *i2c) { struct tda7419_data *tda7419; int i, ret; @@ -630,7 +629,7 @@ static struct i2c_driver tda7419_driver = { .name = "tda7419", .of_match_table = tda7419_of_match, }, - .probe = tda7419_probe, + .probe_new = tda7419_probe, .id_table = tda7419_i2c_id, }; diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index 3d8e8c2276f0..9f7902ec40db 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -111,8 +111,8 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int i2s_set; int sck_pol; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -235,7 +235,6 @@ static const struct snd_soc_component_driver tfa9879_component = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config tfa9879_regmap = { diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index eb2a7870148d..b853507e65a8 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -7,6 +7,7 @@ * Copyright (C) 2013 Sony Mobile Communications Inc. */ +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/regmap.h> @@ -39,12 +40,14 @@ #define TFA989X_I2S_SEL_REG 0x0a #define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */ #define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */ +#define TFA989X_HIDE_UNHIDE_KEY 0x40 #define TFA989X_PWM_CONTROL 0x41 #define TFA989X_CURRENTSENSE1 0x46 #define TFA989X_CURRENTSENSE2 0x47 #define TFA989X_CURRENTSENSE3 0x48 #define TFA989X_CURRENTSENSE4 0x49 +#define TFA9890_REVISION 0x80 #define TFA9895_REVISION 0x12 #define TFA9897_REVISION 0x97 @@ -56,6 +59,7 @@ struct tfa989x_rev { struct tfa989x { const struct tfa989x_rev *rev; struct regulator *vddd_supply; + struct gpio_desc *rcv_gpiod; }; static bool tfa989x_writeable_reg(struct device *dev, unsigned int reg) @@ -99,10 +103,20 @@ static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = { {"Amp Input", "Right", "AIFINR"}, }; +static int tfa989x_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component); + + gpiod_set_value_cansleep(tfa989x->rcv_gpiod, ucontrol->value.enumerated.item[0]); + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + static const char * const mode_text[] = { "Speaker", "Receiver" }; static SOC_ENUM_SINGLE_DECL(mode_enum, TFA989X_I2SREG, TFA989X_I2SREG_RCV, mode_text); static const struct snd_kcontrol_new tfa989x_mode_controls[] = { - SOC_ENUM("Mode", mode_enum), + SOC_ENUM_EXT("Mode", mode_enum, snd_soc_get_enum_double, tfa989x_put_mode), }; static int tfa989x_probe(struct snd_soc_component *component) @@ -124,7 +138,6 @@ static const struct snd_soc_component_driver tfa989x_component = { .num_dapm_routes = ARRAY_SIZE(tfa989x_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const unsigned int tfa989x_rates[] = { @@ -176,6 +189,33 @@ static struct snd_soc_dai_driver tfa989x_dai = { .ops = &tfa989x_dai_ops, }; +static int tfa9890_init(struct regmap *regmap) +{ + int ret; + + /* temporarily allow access to hidden registers */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b); + if (ret) + return ret; + + /* update PLL registers */ + ret = regmap_set_bits(regmap, 0x59, 0x3); + if (ret) + return ret; + + /* hide registers again */ + ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000); + if (ret) + return ret; + + return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1); +} + +static const struct tfa989x_rev tfa9890_rev = { + .rev = TFA9890_REVISION, + .init = tfa9890_init, +}; + static const struct reg_sequence tfa9895_reg_init[] = { /* some other registers must be set for optimal amplifier behaviour */ { TFA989X_BAT_PROT, 0x13ab }, @@ -301,6 +341,12 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c) return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply), "Failed to get vddd regulator\n"); + if (tfa989x->rev->rev == TFA9897_REVISION) { + tfa989x->rcv_gpiod = devm_gpiod_get_optional(dev, "rcv", GPIOD_OUT_LOW); + if (IS_ERR(tfa989x->rcv_gpiod)) + return PTR_ERR(tfa989x->rcv_gpiod); + } + regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -358,6 +404,7 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c) } static const struct of_device_id tfa989x_of_match[] = { + { .compatible = "nxp,tfa9890", .data = &tfa9890_rev }, { .compatible = "nxp,tfa9895", .data = &tfa9895_rev }, { .compatible = "nxp,tfa9897", .data = &tfa9897_rev }, { } diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c new file mode 100644 index 000000000000..a969547708d4 --- /dev/null +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -0,0 +1,1460 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Based on sound/soc/codecs/tlv320aic3x.c by Vladimir Barinov +// +// Copyright (C) 2010 Mistral Solutions Pvt Ltd. +// Author: Shahina Shaik <shahina.s@mistralsolutions.com> +// +// Copyright (C) 2014-2018, Ambarella, Inc. +// Author: Dongge wu <dgwu@ambarella.com> +// +// Copyright (C) 2021 Axis Communications AB +// Author: Ricard Wanderlof <ricardw@axis.com> +// + +#include <dt-bindings/sound/tlv320adc3xxx.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/gpio/driver.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/cdev.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include <sound/initval.h> + +/* + * General definitions defining exported functionality. + */ + +#define ADC3XXX_MICBIAS_PINS 2 + +/* Number of GPIO pins exposed via the gpiolib interface */ +#define ADC3XXX_GPIOS_MAX 2 + +#define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000 +#define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* + * PLL modes, to be used for clk_id for set_sysclk callback. + * + * The default behavior (AUTO) is to take the first matching entry in the clock + * table, which is intended to be the PLL based one if there is more than one. + * + * Setting the clock source using simple-card (clocks or + * system-clock-frequency property) sets clk_id = 0 = ADC3XXX_PLL_AUTO. + */ +#define ADC3XXX_PLL_AUTO 0 /* Use first available mode */ +#define ADC3XXX_PLL_ENABLE 1 /* Use PLL for clock generation */ +#define ADC3XXX_PLL_BYPASS 2 /* Don't use PLL for clock generation */ + +/* Register definitions. */ + +#define ADC3XXX_PAGE_SIZE 128 +#define ADC3XXX_REG(page, reg) ((page * ADC3XXX_PAGE_SIZE) + reg) + +/* + * Page 0 registers. + */ + +#define ADC3XXX_PAGE_SELECT ADC3XXX_REG(0, 0) +#define ADC3XXX_RESET ADC3XXX_REG(0, 1) + +/* 2-3 Reserved */ + +#define ADC3XXX_CLKGEN_MUX ADC3XXX_REG(0, 4) +#define ADC3XXX_PLL_PROG_PR ADC3XXX_REG(0, 5) +#define ADC3XXX_PLL_PROG_J ADC3XXX_REG(0, 6) +#define ADC3XXX_PLL_PROG_D_MSB ADC3XXX_REG(0, 7) +#define ADC3XXX_PLL_PROG_D_LSB ADC3XXX_REG(0, 8) + +/* 9-17 Reserved */ + +#define ADC3XXX_ADC_NADC ADC3XXX_REG(0, 18) +#define ADC3XXX_ADC_MADC ADC3XXX_REG(0, 19) +#define ADC3XXX_ADC_AOSR ADC3XXX_REG(0, 20) +#define ADC3XXX_ADC_IADC ADC3XXX_REG(0, 21) + +/* 23-24 Reserved */ + +#define ADC3XXX_CLKOUT_MUX ADC3XXX_REG(0, 25) +#define ADC3XXX_CLKOUT_M_DIV ADC3XXX_REG(0, 26) +#define ADC3XXX_INTERFACE_CTRL_1 ADC3XXX_REG(0, 27) +#define ADC3XXX_CH_OFFSET_1 ADC3XXX_REG(0, 28) +#define ADC3XXX_INTERFACE_CTRL_2 ADC3XXX_REG(0, 29) +#define ADC3XXX_BCLK_N_DIV ADC3XXX_REG(0, 30) +#define ADC3XXX_INTERFACE_CTRL_3 ADC3XXX_REG(0, 31) +#define ADC3XXX_INTERFACE_CTRL_4 ADC3XXX_REG(0, 32) +#define ADC3XXX_INTERFACE_CTRL_5 ADC3XXX_REG(0, 33) +#define ADC3XXX_I2S_SYNC ADC3XXX_REG(0, 34) +/* 35 Reserved */ +#define ADC3XXX_ADC_FLAG ADC3XXX_REG(0, 36) +#define ADC3XXX_CH_OFFSET_2 ADC3XXX_REG(0, 37) +#define ADC3XXX_I2S_TDM_CTRL ADC3XXX_REG(0, 38) +/* 39-41 Reserved */ +#define ADC3XXX_INTR_FLAG_1 ADC3XXX_REG(0, 42) +#define ADC3XXX_INTR_FLAG_2 ADC3XXX_REG(0, 43) +/* 44 Reserved */ +#define ADC3XXX_INTR_FLAG_ADC1 ADC3XXX_REG(0, 45) +/* 46 Reserved */ +#define ADC3XXX_INTR_FLAG_ADC2 ADC3XXX_REG(0, 47) +#define ADC3XXX_INT1_CTRL ADC3XXX_REG(0, 48) +#define ADC3XXX_INT2_CTRL ADC3XXX_REG(0, 49) +/* 50 Reserved */ +#define ADC3XXX_GPIO2_CTRL ADC3XXX_REG(0, 51) +#define ADC3XXX_GPIO1_CTRL ADC3XXX_REG(0, 52) +#define ADC3XXX_DOUT_CTRL ADC3XXX_REG(0, 53) +/* 54-56 Reserved */ +#define ADC3XXX_SYNC_CTRL_1 ADC3XXX_REG(0, 57) +#define ADC3XXX_SYNC_CTRL_2 ADC3XXX_REG(0, 58) +#define ADC3XXX_CIC_GAIN_CTRL ADC3XXX_REG(0, 59) +/* 60 Reserved */ +#define ADC3XXX_PRB_SELECT ADC3XXX_REG(0, 61) +#define ADC3XXX_INST_MODE_CTRL ADC3XXX_REG(0, 62) +/* 63-79 Reserved */ +#define ADC3XXX_MIC_POLARITY_CTRL ADC3XXX_REG(0, 80) +#define ADC3XXX_ADC_DIGITAL ADC3XXX_REG(0, 81) +#define ADC3XXX_ADC_FGA ADC3XXX_REG(0, 82) +#define ADC3XXX_LADC_VOL ADC3XXX_REG(0, 83) +#define ADC3XXX_RADC_VOL ADC3XXX_REG(0, 84) +#define ADC3XXX_ADC_PHASE_COMP ADC3XXX_REG(0, 85) +#define ADC3XXX_LEFT_CHN_AGC_1 ADC3XXX_REG(0, 86) +#define ADC3XXX_LEFT_CHN_AGC_2 ADC3XXX_REG(0, 87) +#define ADC3XXX_LEFT_CHN_AGC_3 ADC3XXX_REG(0, 88) +#define ADC3XXX_LEFT_CHN_AGC_4 ADC3XXX_REG(0, 89) +#define ADC3XXX_LEFT_CHN_AGC_5 ADC3XXX_REG(0, 90) +#define ADC3XXX_LEFT_CHN_AGC_6 ADC3XXX_REG(0, 91) +#define ADC3XXX_LEFT_CHN_AGC_7 ADC3XXX_REG(0, 92) +#define ADC3XXX_LEFT_AGC_GAIN ADC3XXX_REG(0, 93) +#define ADC3XXX_RIGHT_CHN_AGC_1 ADC3XXX_REG(0, 94) +#define ADC3XXX_RIGHT_CHN_AGC_2 ADC3XXX_REG(0, 95) +#define ADC3XXX_RIGHT_CHN_AGC_3 ADC3XXX_REG(0, 96) +#define ADC3XXX_RIGHT_CHN_AGC_4 ADC3XXX_REG(0, 97) +#define ADC3XXX_RIGHT_CHN_AGC_5 ADC3XXX_REG(0, 98) +#define ADC3XXX_RIGHT_CHN_AGC_6 ADC3XXX_REG(0, 99) +#define ADC3XXX_RIGHT_CHN_AGC_7 ADC3XXX_REG(0, 100) +#define ADC3XXX_RIGHT_AGC_GAIN ADC3XXX_REG(0, 101) +/* 102-127 Reserved */ + +/* + * Page 1 registers. + */ + +/* 1-25 Reserved */ +#define ADC3XXX_DITHER_CTRL ADC3XXX_REG(1, 26) +/* 27-50 Reserved */ +#define ADC3XXX_MICBIAS_CTRL ADC3XXX_REG(1, 51) +#define ADC3XXX_LEFT_PGA_SEL_1 ADC3XXX_REG(1, 52) +/* 53 Reserved */ +#define ADC3XXX_LEFT_PGA_SEL_2 ADC3XXX_REG(1, 54) +#define ADC3XXX_RIGHT_PGA_SEL_1 ADC3XXX_REG(1, 55) +#define ADC3XXX_RIGHT_PGA_SEL_2 ADC3XXX_REG(1, 57) +#define ADC3XXX_LEFT_APGA_CTRL ADC3XXX_REG(1, 59) +#define ADC3XXX_RIGHT_APGA_CTRL ADC3XXX_REG(1, 60) +#define ADC3XXX_LOW_CURRENT_MODES ADC3XXX_REG(1, 61) +#define ADC3XXX_ANALOG_PGA_FLAGS ADC3XXX_REG(1, 62) +/* 63-127 Reserved */ + +/* + * Page 4 registers. First page of coefficient memory for the miniDSP. + */ +#define ADC3XXX_LEFT_ADC_IIR_COEFF_N0_MSB ADC3XXX_REG(4, 8) +#define ADC3XXX_LEFT_ADC_IIR_COEFF_N0_LSB ADC3XXX_REG(4, 9) +#define ADC3XXX_LEFT_ADC_IIR_COEFF_N1_MSB ADC3XXX_REG(4, 10) +#define ADC3XXX_LEFT_ADC_IIR_COEFF_N1_LSB ADC3XXX_REG(4, 11) +#define ADC3XXX_LEFT_ADC_IIR_COEFF_D1_MSB ADC3XXX_REG(4, 12) +#define ADC3XXX_LEFT_ADC_IIR_COEFF_D1_LSB ADC3XXX_REG(4, 13) + +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_N0_MSB ADC3XXX_REG(4, 72) +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_N0_LSB ADC3XXX_REG(4, 73) +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_N1_MSB ADC3XXX_REG(4, 74) +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_N1_LSB ADC3XXX_REG(4, 75) +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_D1_MSB ADC3XXX_REG(4, 76) +#define ADC3XXX_RIGHT_ADC_IIR_COEFF_D1_LSB ADC3XXX_REG(4, 77) + +/* + * Register bits. + */ + +/* PLL Enable bits */ +#define ADC3XXX_ENABLE_PLL_SHIFT 7 +#define ADC3XXX_ENABLE_PLL (1 << ADC3XXX_ENABLE_PLL_SHIFT) +#define ADC3XXX_ENABLE_NADC_SHIFT 7 +#define ADC3XXX_ENABLE_NADC (1 << ADC3XXX_ENABLE_NADC_SHIFT) +#define ADC3XXX_ENABLE_MADC_SHIFT 7 +#define ADC3XXX_ENABLE_MADC (1 << ADC3XXX_ENABLE_MADC_SHIFT) +#define ADC3XXX_ENABLE_BCLK_SHIFT 7 +#define ADC3XXX_ENABLE_BCLK (1 << ADC3XXX_ENABLE_BCLK_SHIFT) + +/* Power bits */ +#define ADC3XXX_LADC_PWR_ON 0x80 +#define ADC3XXX_RADC_PWR_ON 0x40 + +#define ADC3XXX_SOFT_RESET 0x01 +#define ADC3XXX_BCLK_MASTER 0x08 +#define ADC3XXX_WCLK_MASTER 0x04 + +/* Interface register masks */ +#define ADC3XXX_FORMAT_MASK 0xc0 +#define ADC3XXX_FORMAT_SHIFT 6 +#define ADC3XXX_WLENGTH_MASK 0x30 +#define ADC3XXX_WLENGTH_SHIFT 4 +#define ADC3XXX_CLKDIR_MASK 0x0c +#define ADC3XXX_CLKDIR_SHIFT 2 + +/* Interface register bit patterns */ +#define ADC3XXX_FORMAT_I2S (0 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_DSP (1 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_RJF (2 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_LJF (3 << ADC3XXX_FORMAT_SHIFT) + +#define ADC3XXX_IFACE_16BITS (0 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_20BITS (1 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_24BITS (2 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_32BITS (3 << ADC3XXX_WLENGTH_SHIFT) + +/* PLL P/R bit offsets */ +#define ADC3XXX_PLLP_SHIFT 4 +#define ADC3XXX_PLLR_SHIFT 0 +#define ADC3XXX_PLL_PR_MASK 0x7f +#define ADC3XXX_PLLJ_MASK 0x3f +#define ADC3XXX_PLLD_MSB_MASK 0x3f +#define ADC3XXX_PLLD_LSB_MASK 0xff +#define ADC3XXX_NADC_MASK 0x7f +#define ADC3XXX_MADC_MASK 0x7f +#define ADC3XXX_AOSR_MASK 0xff +#define ADC3XXX_IADC_MASK 0xff +#define ADC3XXX_BDIV_MASK 0x7f + +/* PLL_CLKIN bits */ +#define ADC3XXX_PLL_CLKIN_SHIFT 2 +#define ADC3XXX_PLL_CLKIN_MCLK 0x0 +#define ADC3XXX_PLL_CLKIN_BCLK 0x1 +#define ADC3XXX_PLL_CLKIN_ZERO 0x3 + +/* CODEC_CLKIN bits */ +#define ADC3XXX_CODEC_CLKIN_SHIFT 0 +#define ADC3XXX_CODEC_CLKIN_MCLK 0x0 +#define ADC3XXX_CODEC_CLKIN_BCLK 0x1 +#define ADC3XXX_CODEC_CLKIN_PLL_CLK 0x3 + +#define ADC3XXX_USE_PLL ((ADC3XXX_PLL_CLKIN_MCLK << ADC3XXX_PLL_CLKIN_SHIFT) | \ + (ADC3XXX_CODEC_CLKIN_PLL_CLK << ADC3XXX_CODEC_CLKIN_SHIFT)) +#define ADC3XXX_NO_PLL ((ADC3XXX_PLL_CLKIN_ZERO << ADC3XXX_PLL_CLKIN_SHIFT) | \ + (ADC3XXX_CODEC_CLKIN_MCLK << ADC3XXX_CODEC_CLKIN_SHIFT)) + +/* Analog PGA control bits */ +#define ADC3XXX_LPGA_MUTE 0x80 +#define ADC3XXX_RPGA_MUTE 0x80 + +#define ADC3XXX_LPGA_GAIN_MASK 0x7f +#define ADC3XXX_RPGA_GAIN_MASK 0x7f + +/* ADC current modes */ +#define ADC3XXX_ADC_LOW_CURR_MODE 0x01 + +/* Left ADC Input selection bits */ +#define ADC3XXX_LCH_SEL1_SHIFT 0 +#define ADC3XXX_LCH_SEL2_SHIFT 2 +#define ADC3XXX_LCH_SEL3_SHIFT 4 +#define ADC3XXX_LCH_SEL4_SHIFT 6 + +#define ADC3XXX_LCH_SEL1X_SHIFT 0 +#define ADC3XXX_LCH_SEL2X_SHIFT 2 +#define ADC3XXX_LCH_SEL3X_SHIFT 4 +#define ADC3XXX_LCH_COMMON_MODE 0x40 +#define ADC3XXX_BYPASS_LPGA 0x80 + +/* Right ADC Input selection bits */ +#define ADC3XXX_RCH_SEL1_SHIFT 0 +#define ADC3XXX_RCH_SEL2_SHIFT 2 +#define ADC3XXX_RCH_SEL3_SHIFT 4 +#define ADC3XXX_RCH_SEL4_SHIFT 6 + +#define ADC3XXX_RCH_SEL1X_SHIFT 0 +#define ADC3XXX_RCH_SEL2X_SHIFT 2 +#define ADC3XXX_RCH_SEL3X_SHIFT 4 +#define ADC3XXX_RCH_COMMON_MODE 0x40 +#define ADC3XXX_BYPASS_RPGA 0x80 + +/* MICBIAS control bits */ +#define ADC3XXX_MICBIAS_MASK 0x2 +#define ADC3XXX_MICBIAS1_SHIFT 5 +#define ADC3XXX_MICBIAS2_SHIFT 3 + +#define ADC3XXX_ADC_MAX_VOLUME 64 +#define ADC3XXX_ADC_POS_VOL 24 + +/* GPIO control bits (GPIO1_CTRL and GPIO2_CTRL) */ +#define ADC3XXX_GPIO_CTRL_CFG_MASK 0x3c +#define ADC3XXX_GPIO_CTRL_CFG_SHIFT 2 +#define ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK 0x01 +#define ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_SHIFT 0 +#define ADC3XXX_GPIO_CTRL_INPUT_VALUE_MASK 0x02 +#define ADC3XXX_GPIO_CTRL_INPUT_VALUE_SHIFT 1 + +enum adc3xxx_type { + ADC3001 = 0, + ADC3101 +}; + +struct adc3xxx { + struct device *dev; + enum adc3xxx_type type; + struct clk *mclk; + struct regmap *regmap; + struct gpio_desc *rst_pin; + unsigned int pll_mode; + unsigned int sysclk; + unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */ + unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS]; + int master; + u8 page_no; + int use_pll; + struct gpio_chip gpio_chip; +}; + +static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = { + ADC3XXX_GPIO1_CTRL, + ADC3XXX_GPIO2_CTRL +}; + +static const unsigned int adc3xxx_micbias_shift[ADC3XXX_MICBIAS_PINS] = { + ADC3XXX_MICBIAS1_SHIFT, + ADC3XXX_MICBIAS2_SHIFT +}; + +static const struct reg_default adc3xxx_defaults[] = { + /* Page 0 */ + { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x00 }, + { 4, 0x00 }, { 5, 0x11 }, { 6, 0x04 }, { 7, 0x00 }, + { 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x00 }, + { 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x00 }, + { 16, 0x00 }, { 17, 0x00 }, { 18, 0x01 }, { 19, 0x01 }, + { 20, 0x80 }, { 21, 0x80 }, { 22, 0x04 }, { 23, 0x00 }, + { 24, 0x00 }, { 25, 0x00 }, { 26, 0x01 }, { 27, 0x00 }, + { 28, 0x00 }, { 29, 0x02 }, { 30, 0x01 }, { 31, 0x00 }, + { 32, 0x00 }, { 33, 0x10 }, { 34, 0x00 }, { 35, 0x00 }, + { 36, 0x00 }, { 37, 0x00 }, { 38, 0x02 }, { 39, 0x00 }, + { 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x00 }, + { 44, 0x00 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 }, + { 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x00 }, + { 52, 0x00 }, { 53, 0x12 }, { 54, 0x00 }, { 55, 0x00 }, + { 56, 0x00 }, { 57, 0x00 }, { 58, 0x00 }, { 59, 0x44 }, + { 60, 0x00 }, { 61, 0x01 }, { 62, 0x00 }, { 63, 0x00 }, + { 64, 0x00 }, { 65, 0x00 }, { 66, 0x00 }, { 67, 0x00 }, + { 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 }, + { 72, 0x00 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 }, + { 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 }, + { 80, 0x00 }, { 81, 0x00 }, { 82, 0x88 }, { 83, 0x00 }, + { 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 }, + { 88, 0x7f }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 }, + { 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 }, + { 96, 0x7f }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 }, + { 100, 0x00 }, { 101, 0x00 }, { 102, 0x00 }, { 103, 0x00 }, + { 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 }, + { 108, 0x00 }, { 109, 0x00 }, { 110, 0x00 }, { 111, 0x00 }, + { 112, 0x00 }, { 113, 0x00 }, { 114, 0x00 }, { 115, 0x00 }, + { 116, 0x00 }, { 117, 0x00 }, { 118, 0x00 }, { 119, 0x00 }, + { 120, 0x00 }, { 121, 0x00 }, { 122, 0x00 }, { 123, 0x00 }, + { 124, 0x00 }, { 125, 0x00 }, { 126, 0x00 }, { 127, 0x00 }, + + /* Page 1 */ + { 128, 0x00 }, { 129, 0x00 }, { 130, 0x00 }, { 131, 0x00 }, + { 132, 0x00 }, { 133, 0x00 }, { 134, 0x00 }, { 135, 0x00 }, + { 136, 0x00 }, { 137, 0x00 }, { 138, 0x00 }, { 139, 0x00 }, + { 140, 0x00 }, { 141, 0x00 }, { 142, 0x00 }, { 143, 0x00 }, + { 144, 0x00 }, { 145, 0x00 }, { 146, 0x00 }, { 147, 0x00 }, + { 148, 0x00 }, { 149, 0x00 }, { 150, 0x00 }, { 151, 0x00 }, + { 152, 0x00 }, { 153, 0x00 }, { 154, 0x00 }, { 155, 0x00 }, + { 156, 0x00 }, { 157, 0x00 }, { 158, 0x00 }, { 159, 0x00 }, + { 160, 0x00 }, { 161, 0x00 }, { 162, 0x00 }, { 163, 0x00 }, + { 164, 0x00 }, { 165, 0x00 }, { 166, 0x00 }, { 167, 0x00 }, + { 168, 0x00 }, { 169, 0x00 }, { 170, 0x00 }, { 171, 0x00 }, + { 172, 0x00 }, { 173, 0x00 }, { 174, 0x00 }, { 175, 0x00 }, + { 176, 0x00 }, { 177, 0x00 }, { 178, 0x00 }, { 179, 0x00 }, + { 180, 0xff }, { 181, 0x00 }, { 182, 0x3f }, { 183, 0xff }, + { 184, 0x00 }, { 185, 0x3f }, { 186, 0x00 }, { 187, 0x80 }, + { 188, 0x80 }, { 189, 0x00 }, { 190, 0x00 }, { 191, 0x00 }, + + /* Page 4 */ + { 1024, 0x00 }, { 1026, 0x01 }, { 1027, 0x17 }, + { 1028, 0x01 }, { 1029, 0x17 }, { 1030, 0x7d }, { 1031, 0xd3 }, + { 1032, 0x7f }, { 1033, 0xff }, { 1034, 0x00 }, { 1035, 0x00 }, + { 1036, 0x00 }, { 1037, 0x00 }, { 1038, 0x7f }, { 1039, 0xff }, + { 1040, 0x00 }, { 1041, 0x00 }, { 1042, 0x00 }, { 1043, 0x00 }, + { 1044, 0x00 }, { 1045, 0x00 }, { 1046, 0x00 }, { 1047, 0x00 }, + { 1048, 0x7f }, { 1049, 0xff }, { 1050, 0x00 }, { 1051, 0x00 }, + { 1052, 0x00 }, { 1053, 0x00 }, { 1054, 0x00 }, { 1055, 0x00 }, + { 1056, 0x00 }, { 1057, 0x00 }, { 1058, 0x7f }, { 1059, 0xff }, + { 1060, 0x00 }, { 1061, 0x00 }, { 1062, 0x00 }, { 1063, 0x00 }, + { 1064, 0x00 }, { 1065, 0x00 }, { 1066, 0x00 }, { 1067, 0x00 }, + { 1068, 0x7f }, { 1069, 0xff }, { 1070, 0x00 }, { 1071, 0x00 }, + { 1072, 0x00 }, { 1073, 0x00 }, { 1074, 0x00 }, { 1075, 0x00 }, + { 1076, 0x00 }, { 1077, 0x00 }, { 1078, 0x7f }, { 1079, 0xff }, + { 1080, 0x00 }, { 1081, 0x00 }, { 1082, 0x00 }, { 1083, 0x00 }, + { 1084, 0x00 }, { 1085, 0x00 }, { 1086, 0x00 }, { 1087, 0x00 }, + { 1088, 0x00 }, { 1089, 0x00 }, { 1090, 0x00 }, { 1091, 0x00 }, + { 1092, 0x00 }, { 1093, 0x00 }, { 1094, 0x00 }, { 1095, 0x00 }, + { 1096, 0x00 }, { 1097, 0x00 }, { 1098, 0x00 }, { 1099, 0x00 }, + { 1100, 0x00 }, { 1101, 0x00 }, { 1102, 0x00 }, { 1103, 0x00 }, + { 1104, 0x00 }, { 1105, 0x00 }, { 1106, 0x00 }, { 1107, 0x00 }, + { 1108, 0x00 }, { 1109, 0x00 }, { 1110, 0x00 }, { 1111, 0x00 }, + { 1112, 0x00 }, { 1113, 0x00 }, { 1114, 0x00 }, { 1115, 0x00 }, + { 1116, 0x00 }, { 1117, 0x00 }, { 1118, 0x00 }, { 1119, 0x00 }, + { 1120, 0x00 }, { 1121, 0x00 }, { 1122, 0x00 }, { 1123, 0x00 }, + { 1124, 0x00 }, { 1125, 0x00 }, { 1126, 0x00 }, { 1127, 0x00 }, + { 1128, 0x00 }, { 1129, 0x00 }, { 1130, 0x00 }, { 1131, 0x00 }, + { 1132, 0x00 }, { 1133, 0x00 }, { 1134, 0x00 }, { 1135, 0x00 }, + { 1136, 0x00 }, { 1137, 0x00 }, { 1138, 0x00 }, { 1139, 0x00 }, + { 1140, 0x00 }, { 1141, 0x00 }, { 1142, 0x00 }, { 1143, 0x00 }, + { 1144, 0x00 }, { 1145, 0x00 }, { 1146, 0x00 }, { 1147, 0x00 }, + { 1148, 0x00 }, { 1149, 0x00 }, { 1150, 0x00 }, { 1151, 0x00 }, +}; + +static bool adc3xxx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADC3XXX_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg adc3xxx_ranges[] = { + { + .range_min = 0, + .range_max = 5 * ADC3XXX_PAGE_SIZE, + .selector_reg = ADC3XXX_PAGE_SELECT, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = ADC3XXX_PAGE_SIZE, + } +}; + +static const struct regmap_config adc3xxx_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = adc3xxx_defaults, + .num_reg_defaults = ARRAY_SIZE(adc3xxx_defaults), + + .volatile_reg = adc3xxx_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + + .ranges = adc3xxx_ranges, + .num_ranges = ARRAY_SIZE(adc3xxx_ranges), + .max_register = 5 * ADC3XXX_PAGE_SIZE, +}; + +struct adc3xxx_rate_divs { + u32 mclk; + u32 rate; + u8 pll_p; + u8 pll_r; + u8 pll_j; + u16 pll_d; + u8 nadc; + u8 madc; + u8 aosr; +}; + +/* + * PLL and Clock settings. + * If p member is 0, PLL is not used. + * The order of the entries in this table have the PLL entries before + * the non-PLL entries, so that the PLL modes are preferred unless + * the PLL mode setting says otherwise. + */ +static const struct adc3xxx_rate_divs adc3xxx_divs[] = { + /* mclk, rate, p, r, j, d, nadc, madc, aosr */ + /* 8k rate */ + { 12000000, 8000, 1, 1, 7, 1680, 42, 2, 128 }, + { 12288000, 8000, 1, 1, 7, 0000, 42, 2, 128 }, + /* 11.025k rate */ + { 12000000, 11025, 1, 1, 6, 8208, 29, 2, 128 }, + /* 16k rate */ + { 12000000, 16000, 1, 1, 7, 1680, 21, 2, 128 }, + { 12288000, 16000, 1, 1, 7, 0000, 21, 2, 128 }, + /* 22.05k rate */ + { 12000000, 22050, 1, 1, 7, 560, 15, 2, 128 }, + /* 32k rate */ + { 12000000, 32000, 1, 1, 8, 1920, 12, 2, 128 }, + { 12288000, 32000, 1, 1, 8, 0000, 12, 2, 128 }, + /* 44.1k rate */ + { 12000000, 44100, 1, 1, 7, 5264, 8, 2, 128 }, + /* 48k rate */ + { 12000000, 48000, 1, 1, 7, 1680, 7, 2, 128 }, + { 12288000, 48000, 1, 1, 7, 0000, 7, 2, 128 }, + { 24576000, 48000, 1, 1, 3, 5000, 7, 2, 128 }, /* With PLL */ + { 24576000, 48000, 0, 0, 0, 0000, 2, 2, 128 }, /* Without PLL */ + /* 88.2k rate */ + { 12000000, 88200, 1, 1, 7, 5264, 4, 4, 64 }, + /* 96k rate */ + { 12000000, 96000, 1, 1, 8, 1920, 4, 4, 64 }, +}; + +static int adc3xxx_get_divs(struct device *dev, int mclk, int rate, int pll_mode) +{ + int i; + + dev_dbg(dev, "mclk = %d, rate = %d, clock mode %u\n", + mclk, rate, pll_mode); + for (i = 0; i < ARRAY_SIZE(adc3xxx_divs); i++) { + const struct adc3xxx_rate_divs *mode = &adc3xxx_divs[i]; + + /* Skip this entry if it doesn't fulfill the intended clock + * mode requirement. We consider anything besides the two + * modes below to be the same as ADC3XXX_PLL_AUTO. + */ + if ((pll_mode == ADC3XXX_PLL_BYPASS && mode->pll_p) || + (pll_mode == ADC3XXX_PLL_ENABLE && !mode->pll_p)) + continue; + + if (mode->rate == rate && mode->mclk == mclk) + return i; + } + + dev_info(dev, "Master clock rate %d and sample rate %d is not supported\n", + mclk, rate); + return -EINVAL; +} + +static int adc3xxx_pll_delay(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + /* 10msec delay needed after PLL power-up to allow + * PLL and dividers to stabilize (datasheet p13). + */ + usleep_range(10000, 20000); + + return 0; +} + +static int adc3xxx_coefficient_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int numcoeff = kcontrol->private_value >> 16; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = numcoeff; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; /* all coefficients are 16 bit */ + return 0; +} + +static int adc3xxx_coefficient_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int numcoeff = kcontrol->private_value >> 16; + int reg = kcontrol->private_value & 0xffff; + int index = 0; + + for (index = 0; index < numcoeff; index++) { + unsigned int value_msb, value_lsb, value; + + value_msb = snd_soc_component_read(component, reg++); + if ((int)value_msb < 0) + return (int)value_msb; + + value_lsb = snd_soc_component_read(component, reg++); + if ((int)value_lsb < 0) + return (int)value_lsb; + + value = (value_msb << 8) | value_lsb; + ucontrol->value.integer.value[index] = value; + } + + return 0; +} + +static int adc3xxx_coefficient_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int numcoeff = kcontrol->private_value >> 16; + int reg = kcontrol->private_value & 0xffff; + int index = 0; + int ret; + + for (index = 0; index < numcoeff; index++) { + unsigned int value = ucontrol->value.integer.value[index]; + unsigned int value_msb = (value >> 8) & 0xff; + unsigned int value_lsb = value & 0xff; + + ret = snd_soc_component_write(component, reg++, value_msb); + if (ret) + return ret; + + ret = snd_soc_component_write(component, reg++, value_lsb); + if (ret) + return ret; + } + + return 0; +} + +/* All on-chip filters have coefficients which are expressed in terms of + * 16 bit values, so represent them as strings of 16-bit integers. + */ +#define TI_COEFFICIENTS(xname, reg, numcoeffs) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = adc3xxx_coefficient_info, \ + .get = adc3xxx_coefficient_get,\ + .put = adc3xxx_coefficient_put, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .private_value = reg | (numcoeffs << 16) \ +} + +static const char * const adc_softstepping_text[] = { "1 step", "2 step", "off" }; +static SOC_ENUM_SINGLE_DECL(adc_softstepping_enum, ADC3XXX_ADC_DIGITAL, 0, + adc_softstepping_text); + +static const char * const multiplier_text[] = { "1", "2", "4", "8", "16", "32", "64", "128" }; +static SOC_ENUM_SINGLE_DECL(left_agc_attack_mult_enum, + ADC3XXX_LEFT_CHN_AGC_4, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(right_agc_attack_mult_enum, + ADC3XXX_RIGHT_CHN_AGC_4, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(left_agc_decay_mult_enum, + ADC3XXX_LEFT_CHN_AGC_5, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(right_agc_decay_mult_enum, + ADC3XXX_RIGHT_CHN_AGC_5, 0, multiplier_text); + +static const char * const dither_dc_offset_text[] = { + "0mV", "15mV", "30mV", "45mV", "60mV", "75mV", "90mV", "105mV", + "-15mV", "-30mV", "-45mV", "-60mV", "-75mV", "-90mV", "-105mV" +}; +static const unsigned int dither_dc_offset_values[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15 +}; +static SOC_VALUE_ENUM_DOUBLE_DECL(dither_dc_offset_enum, + ADC3XXX_DITHER_CTRL, + 4, 0, 0xf, dither_dc_offset_text, + dither_dc_offset_values); + +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_fine_tlv, -40, 10, 0); +/* AGC target: 8 values: -5.5, -8, -10, -12, -14, -17, -20, -24 dB */ +/* It would be nice to declare these in the order above, but empirically + * TLV_DB_SCALE_ITEM doesn't take lightly to the increment (second) parameter + * being negative, despite there being examples to the contrary in other + * drivers. So declare these in the order from lowest to highest, and + * set the invert flag in the SOC_DOUBLE_R_TLV declaration instead. + */ +static const DECLARE_TLV_DB_RANGE(agc_target_tlv, + 0, 0, TLV_DB_SCALE_ITEM(-2400, 0, 0), + 1, 3, TLV_DB_SCALE_ITEM(-2000, 300, 0), + 4, 6, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 7, 7, TLV_DB_SCALE_ITEM(-550, 0, 0)); +/* Since the 'disabled' value (mute) is at the highest value in the dB + * range (i.e. just before -32 dB) rather than the lowest, we need to resort + * to using a TLV_DB_RANGE in order to get the mute value in the right place. + */ +static const DECLARE_TLV_DB_RANGE(agc_thresh_tlv, + 0, 30, TLV_DB_SCALE_ITEM(-9000, 200, 0), + 31, 31, TLV_DB_SCALE_ITEM(0, 0, 1)); /* disabled = mute */ +/* AGC hysteresis: 4 values: 1, 2, 4 dB, disabled (= mute) */ +static const DECLARE_TLV_DB_RANGE(agc_hysteresis_tlv, + 0, 1, TLV_DB_SCALE_ITEM(100, 100, 0), + 2, 2, TLV_DB_SCALE_ITEM(400, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(0, 0, 1)); /* disabled = mute */ +static const DECLARE_TLV_DB_SCALE(agc_max_tlv, 0, 50, 0); +/* Input attenuation: -6 dB or 0 dB */ +static const DECLARE_TLV_DB_SCALE(input_attenuation_tlv, -600, 600, 0); + +static const struct snd_kcontrol_new adc3xxx_snd_controls[] = { + SOC_DOUBLE_R_TLV("PGA Capture Volume", ADC3XXX_LEFT_APGA_CTRL, + ADC3XXX_RIGHT_APGA_CTRL, 0, 80, 0, pga_tlv), + SOC_DOUBLE("PGA Capture Switch", ADC3XXX_ADC_FGA, 7, 3, 1, 1), + SOC_DOUBLE_R("AGC Capture Switch", ADC3XXX_LEFT_CHN_AGC_1, + ADC3XXX_RIGHT_CHN_AGC_1, 7, 1, 0), + SOC_DOUBLE_R_TLV("AGC Target Level Capture Volume", ADC3XXX_LEFT_CHN_AGC_1, + ADC3XXX_RIGHT_CHN_AGC_2, 4, 0x07, 1, agc_target_tlv), + SOC_DOUBLE_R_TLV("AGC Noise Threshold Capture Volume", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 1, 0x1f, 1, agc_thresh_tlv), + SOC_DOUBLE_R_TLV("AGC Hysteresis Capture Volume", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 6, 3, 0, agc_hysteresis_tlv), + SOC_DOUBLE_R("AGC Clip Stepping Capture Switch", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 0, 1, 0), + /* + * Oddly enough, the data sheet says the default value + * for the left/right AGC maximum gain register field + * (ADC3XXX_LEFT/RIGHT_CHN_AGC_3 bits 0..6) is 0x7f = 127 + * (verified empirically) even though this value (indeed, above + * 0x50) is specified as 'Reserved. Do not use.' in the accompanying + * table in the data sheet. + */ + SOC_DOUBLE_R_TLV("AGC Maximum Capture Volume", ADC3XXX_LEFT_CHN_AGC_3, + ADC3XXX_RIGHT_CHN_AGC_3, 0, 0x50, 0, agc_max_tlv), + SOC_DOUBLE_R("AGC Attack Time", ADC3XXX_LEFT_CHN_AGC_4, + ADC3XXX_RIGHT_CHN_AGC_4, 3, 0x1f, 0), + /* Would like to have the multipliers as LR pairs, but there is + * no SOC_ENUM_foo which accepts two values in separate registers. + */ + SOC_ENUM("AGC Left Attack Time Multiplier", left_agc_attack_mult_enum), + SOC_ENUM("AGC Right Attack Time Multiplier", right_agc_attack_mult_enum), + SOC_DOUBLE_R("AGC Decay Time", ADC3XXX_LEFT_CHN_AGC_5, + ADC3XXX_RIGHT_CHN_AGC_5, 3, 0x1f, 0), + SOC_ENUM("AGC Left Decay Time Multiplier", left_agc_decay_mult_enum), + SOC_ENUM("AGC Right Decay Time Multiplier", right_agc_decay_mult_enum), + SOC_DOUBLE_R("AGC Noise Debounce", ADC3XXX_LEFT_CHN_AGC_6, + ADC3XXX_RIGHT_CHN_AGC_6, 0, 0x1f, 0), + SOC_DOUBLE_R("AGC Signal Debounce", ADC3XXX_LEFT_CHN_AGC_7, + ADC3XXX_RIGHT_CHN_AGC_7, 0, 0x0f, 0), + /* Read only register */ + SOC_DOUBLE_R_S_TLV("AGC Applied Capture Volume", ADC3XXX_LEFT_AGC_GAIN, + ADC3XXX_RIGHT_AGC_GAIN, 0, -24, 40, 6, 0, adc_tlv), + /* ADC soft stepping */ + SOC_ENUM("ADC Soft Stepping", adc_softstepping_enum), + /* Left/Right Input attenuation */ + SOC_SINGLE_TLV("Left Input IN_1L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_2L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_3L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_1R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_2L_3L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 6, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_1L_1R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_2R_3R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_1R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_2R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_3R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_1L Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_2R_3R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 6, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_1L_1R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_2L_3L Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 2, 1, 1, input_attenuation_tlv), + SOC_DOUBLE_R_S_TLV("ADC Volume Control Capture Volume", ADC3XXX_LADC_VOL, + ADC3XXX_RADC_VOL, 0, -24, 40, 6, 0, adc_tlv), + /* Empirically, the following doesn't work the way it's supposed + * to. Values 0, -0.1, -0.2 and -0.3 dB result in the same level, and + * -0.4 dB drops about 0.12 dB on a specific chip. + */ + SOC_DOUBLE_TLV("ADC Fine Volume Control Capture Volume", ADC3XXX_ADC_FGA, + 4, 0, 4, 1, adc_fine_tlv), + SOC_SINGLE("Left ADC Unselected CM Bias Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 6, 1, 0), + SOC_SINGLE("Right ADC Unselected CM Bias Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 6, 1, 0), + SOC_ENUM("Dither Control DC Offset", dither_dc_offset_enum), + + /* Coefficient memory for miniDSP. */ + /* For the default PRB_R1 processing block, the only available + * filter is the first order IIR. + */ + + TI_COEFFICIENTS("Left ADC IIR Coefficients N0 N1 D1", + ADC3XXX_LEFT_ADC_IIR_COEFF_N0_MSB, 3), + + TI_COEFFICIENTS("Right ADC IIR Coefficients N0 N1 D1", + ADC3XXX_RIGHT_ADC_IIR_COEFF_N0_MSB, 3), +}; + +/* Left input selection, Single Ended inputs and Differential inputs */ +static const struct snd_kcontrol_new left_input_mixer_controls[] = { + SOC_DAPM_SINGLE("IN_1L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 1, 0x1, 1), + SOC_DAPM_SINGLE("IN_2L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_3L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2L_3L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 7, 0x1, 1), + SOC_DAPM_SINGLE("DIF_1L_1R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2R_3R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_1R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 1, 0x1, 1), +}; + +/* Right input selection, Single Ended inputs and Differential inputs */ +static const struct snd_kcontrol_new right_input_mixer_controls[] = { + SOC_DAPM_SINGLE("IN_1R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 1, 0x1, 1), + SOC_DAPM_SINGLE("IN_2R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_3R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2R_3R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 7, 0x1, 1), + SOC_DAPM_SINGLE("DIF_1L_1R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2L_3L Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_1L Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 1, 0x1, 1), +}; + +/* Left Digital Mic input for left ADC */ +static const struct snd_kcontrol_new left_input_dmic_controls[] = { + SOC_DAPM_SINGLE("Left ADC Capture Switch", + ADC3XXX_ADC_DIGITAL, 3, 0x1, 0), +}; + +/* Right Digital Mic input for Right ADC */ +static const struct snd_kcontrol_new right_input_dmic_controls[] = { + SOC_DAPM_SINGLE("Right ADC Capture Switch", + ADC3XXX_ADC_DIGITAL, 2, 0x1, 0), +}; + +/* DAPM widgets */ +static const struct snd_soc_dapm_widget adc3xxx_dapm_widgets[] = { + + /* Left Input Selection */ + SND_SOC_DAPM_MIXER("Left Input", SND_SOC_NOPM, 0, 0, + &left_input_mixer_controls[0], + ARRAY_SIZE(left_input_mixer_controls)), + /* Right Input Selection */ + SND_SOC_DAPM_MIXER("Right Input", SND_SOC_NOPM, 0, 0, + &right_input_mixer_controls[0], + ARRAY_SIZE(right_input_mixer_controls)), + /* PGA selection */ + SND_SOC_DAPM_PGA("Left PGA", ADC3XXX_LEFT_APGA_CTRL, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right PGA", ADC3XXX_RIGHT_APGA_CTRL, 7, 1, NULL, 0), + + /* Digital Microphone Input Control for Left/Right ADC */ + SND_SOC_DAPM_MIXER("Left DMic Input", SND_SOC_NOPM, 0, 0, + &left_input_dmic_controls[0], + ARRAY_SIZE(left_input_dmic_controls)), + SND_SOC_DAPM_MIXER("Right DMic Input", SND_SOC_NOPM, 0, 0, + &right_input_dmic_controls[0], + ARRAY_SIZE(right_input_dmic_controls)), + + /* Left/Right ADC */ + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ADC3XXX_ADC_DIGITAL, 7, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ADC3XXX_ADC_DIGITAL, 6, 0), + + /* Inputs */ + SND_SOC_DAPM_INPUT("IN_1L"), + SND_SOC_DAPM_INPUT("IN_1R"), + SND_SOC_DAPM_INPUT("IN_2L"), + SND_SOC_DAPM_INPUT("IN_2R"), + SND_SOC_DAPM_INPUT("IN_3L"), + SND_SOC_DAPM_INPUT("IN_3R"), + SND_SOC_DAPM_INPUT("DIFL_1L_1R"), + SND_SOC_DAPM_INPUT("DIFL_2L_3L"), + SND_SOC_DAPM_INPUT("DIFL_2R_3R"), + SND_SOC_DAPM_INPUT("DIFR_1L_1R"), + SND_SOC_DAPM_INPUT("DIFR_2L_3L"), + SND_SOC_DAPM_INPUT("DIFR_2R_3R"), + SND_SOC_DAPM_INPUT("DMic_L"), + SND_SOC_DAPM_INPUT("DMic_R"), + + /* Digital audio interface output */ + SND_SOC_DAPM_AIF_OUT("AIF_OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Clocks */ + SND_SOC_DAPM_SUPPLY("PLL_CLK", ADC3XXX_PLL_PROG_PR, ADC3XXX_ENABLE_PLL_SHIFT, + 0, adc3xxx_pll_delay, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("ADC_CLK", ADC3XXX_ADC_NADC, ADC3XXX_ENABLE_NADC_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", ADC3XXX_ADC_MADC, ADC3XXX_ENABLE_MADC_SHIFT, + 0, NULL, 0), + + /* This refers to the generated BCLK in master mode. */ + SND_SOC_DAPM_SUPPLY("BCLK", ADC3XXX_BCLK_N_DIV, ADC3XXX_ENABLE_BCLK_SHIFT, + 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route adc3xxx_intercon[] = { + /* Left input selection from switches */ + { "Left Input", "IN_1L Capture Switch", "IN_1L" }, + { "Left Input", "IN_2L Capture Switch", "IN_2L" }, + { "Left Input", "IN_3L Capture Switch", "IN_3L" }, + { "Left Input", "DIF_2L_3L Capture Switch", "DIFL_2L_3L" }, + { "Left Input", "DIF_1L_1R Capture Switch", "DIFL_1L_1R" }, + { "Left Input", "DIF_2R_3R Capture Switch", "DIFL_2R_3R" }, + { "Left Input", "IN_1R Capture Switch", "IN_1R" }, + + /* Left input selection to left PGA */ + { "Left PGA", NULL, "Left Input" }, + + /* Left PGA to left ADC */ + { "Left ADC", NULL, "Left PGA" }, + + /* Right input selection from switches */ + { "Right Input", "IN_1R Capture Switch", "IN_1R" }, + { "Right Input", "IN_2R Capture Switch", "IN_2R" }, + { "Right Input", "IN_3R Capture Switch", "IN_3R" }, + { "Right Input", "DIF_2R_3R Capture Switch", "DIFR_2R_3R" }, + { "Right Input", "DIF_1L_1R Capture Switch", "DIFR_1L_1R" }, + { "Right Input", "DIF_2L_3L Capture Switch", "DIFR_2L_3L" }, + { "Right Input", "IN_1L Capture Switch", "IN_1L" }, + + /* Right input selection to right PGA */ + { "Right PGA", NULL, "Right Input" }, + + /* Right PGA to right ADC */ + { "Right ADC", NULL, "Right PGA" }, + + /* Left DMic Input selection from switch */ + { "Left DMic Input", "Left ADC Capture Switch", "DMic_L" }, + + /* Left DMic to left ADC */ + { "Left ADC", NULL, "Left DMic Input" }, + + /* Right DMic Input selection from switch */ + { "Right DMic Input", "Right ADC Capture Switch", "DMic_R" }, + + /* Right DMic to right ADC */ + { "Right ADC", NULL, "Right DMic Input" }, + + /* ADC to AIF output */ + { "AIF_OUT", NULL, "Left ADC" }, + { "AIF_OUT", NULL, "Right ADC" }, + + /* Clocking */ + { "ADC_MOD_CLK", NULL, "ADC_CLK" }, + { "Left ADC", NULL, "ADC_MOD_CLK" }, + { "Right ADC", NULL, "ADC_MOD_CLK" }, + + { "BCLK", NULL, "ADC_CLK" }, +}; + +static const struct snd_soc_dapm_route adc3xxx_pll_intercon[] = { + { "ADC_CLK", NULL, "PLL_CLK" }, +}; + +static const struct snd_soc_dapm_route adc3xxx_bclk_out_intercon[] = { + { "AIF_OUT", NULL, "BCLK" } +}; + +static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + + if (offset >= ADC3XXX_GPIOS_MAX) + return -EINVAL; + + /* GPIO1 is offset 0, GPIO2 is offset 1 */ + /* We check here that the GPIO pins are either not configured in the + * DT, or that they purposely are set as outputs. + * (Input mode not yet implemented). + */ + if (adc3xxx->gpio_cfg[offset] != 0 && + adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) + return -EINVAL; + + return 0; +} + +static int adc3xxx_gpio_direction_out(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + + /* Set GPIO output function. */ + return regmap_update_bits(adc3xxx->regmap, + adc3xxx_gpio_ctrl_reg[offset], + ADC3XXX_GPIO_CTRL_CFG_MASK | + ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK, + ADC3XXX_GPIO_GPO << ADC3XXX_GPIO_CTRL_CFG_SHIFT | + !!value << ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_SHIFT); +} + +/* With only GPIO outputs configured, we never get the .direction_out call, + * so we set the output mode and output value in the same call. Hence + * .set in practice does the same thing as .direction_out . + */ +static void adc3xxx_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + (void) adc3xxx_gpio_direction_out(chip, offset, value); +} + +/* Even though we only support GPIO output for now, some GPIO clients + * want to read the current pin state using the .get callback. + */ +static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + unsigned int regval; + int ret; + + /* We only allow output pins, so just read the value set in the output + * pin register field. + */ + ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], ®val); + if (ret) + return ret; + return !!(regval & ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK); +} + +static const struct gpio_chip adc3xxx_gpio_chip = { + .label = "adc3xxx", + .owner = THIS_MODULE, + .request = adc3xxx_gpio_request, + .direction_output = adc3xxx_gpio_direction_out, + .set = adc3xxx_gpio_set, + .get = adc3xxx_gpio_get, + .can_sleep = 1, +}; + +static void adc3xxx_free_gpio(struct adc3xxx *adc3xxx) +{ + gpiochip_remove(&adc3xxx->gpio_chip); +} + +static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) +{ + int gpio, micbias; + int ret; + + adc3xxx->gpio_chip = adc3xxx_gpio_chip; + adc3xxx->gpio_chip.ngpio = ADC3XXX_GPIOS_MAX; + adc3xxx->gpio_chip.parent = adc3xxx->dev; + adc3xxx->gpio_chip.base = -1; + + ret = gpiochip_add_data(&adc3xxx->gpio_chip, adc3xxx); + if (ret) + dev_err(adc3xxx->dev, "Failed to add gpios: %d\n", ret); + + /* Set up potential GPIO configuration from the devicetree. + * This allows us to set up things which are not software + * controllable GPIOs, such as PDM microphone I/O, + */ + for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) { + unsigned int cfg = adc3xxx->gpio_cfg[gpio]; + + if (cfg) { + cfg--; /* actual value to use is stored +1 */ + regmap_update_bits(adc3xxx->regmap, + adc3xxx_gpio_ctrl_reg[gpio], + ADC3XXX_GPIO_CTRL_CFG_MASK, + cfg << ADC3XXX_GPIO_CTRL_CFG_SHIFT); + } + } + + /* Set up micbias voltage */ + for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) { + unsigned int vg = adc3xxx->micbias_vg[micbias]; + + regmap_update_bits(adc3xxx->regmap, + ADC3XXX_MICBIAS_CTRL, + ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias], + vg << adc3xxx_micbias_shift[micbias]); + } +} + +static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *cfg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + unsigned int val; + + if (!of_property_read_u32(np, propname, &val)) { + if (val & ~15 || val == 7 || val >= 11) { + dev_err(dev, "Invalid property value for '%s'\n", propname); + return -EINVAL; + } + if (val == ADC3XXX_GPIO_GPI) + dev_warn(dev, "GPIO Input read not yet implemented\n"); + *cfg = val + 1; /* 0 => not set up, all others shifted +1 */ + } + return 0; +} + +static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *vg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + unsigned int val; + + if (!of_property_read_u32(np, propname, &val)) { + if (val >= ADC3XXX_MICBIAS_AVDD) { + dev_err(dev, "Invalid property value for '%s'\n", propname); + return -EINVAL; + } + *vg = val; + } + return 0; +} + +static int adc3xxx_parse_pll_mode(uint32_t val, unsigned int *pll_mode) +{ + if (val != ADC3XXX_PLL_ENABLE && val != ADC3XXX_PLL_BYPASS && + val != ADC3XXX_PLL_AUTO) + return -EINVAL; + + *pll_mode = val; + + return 0; +} + +static void adc3xxx_setup_pll(struct snd_soc_component *component, + int div_entry) +{ + int i = div_entry; + + /* P & R values */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_PR, + (adc3xxx_divs[i].pll_p << ADC3XXX_PLLP_SHIFT) | + (adc3xxx_divs[i].pll_r << ADC3XXX_PLLR_SHIFT)); + /* J value */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_J, + adc3xxx_divs[i].pll_j & ADC3XXX_PLLJ_MASK); + /* D value */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_D_LSB, + adc3xxx_divs[i].pll_d & ADC3XXX_PLLD_LSB_MASK); + snd_soc_component_write(component, ADC3XXX_PLL_PROG_D_MSB, + (adc3xxx_divs[i].pll_d >> 8) & ADC3XXX_PLLD_MSB_MASK); +} + +static int adc3xxx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component); + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + int i, width = 16; + u8 iface_len, bdiv; + + i = adc3xxx_get_divs(component->dev, adc3xxx->sysclk, + params_rate(params), adc3xxx->pll_mode); + + if (i < 0) + return i; + + /* select data word length */ + switch (params_width(params)) { + case 16: + iface_len = ADC3XXX_IFACE_16BITS; + width = 16; + break; + case 20: + iface_len = ADC3XXX_IFACE_20BITS; + width = 20; + break; + case 24: + iface_len = ADC3XXX_IFACE_24BITS; + width = 24; + break; + case 32: + iface_len = ADC3XXX_IFACE_32BITS; + width = 32; + break; + default: + dev_err(component->dev, "Unsupported serial data format\n"); + return -EINVAL; + } + snd_soc_component_update_bits(component, ADC3XXX_INTERFACE_CTRL_1, + ADC3XXX_WLENGTH_MASK, iface_len); + if (adc3xxx_divs[i].pll_p) { /* If PLL used for this mode */ + adc3xxx_setup_pll(component, i); + snd_soc_component_write(component, ADC3XXX_CLKGEN_MUX, ADC3XXX_USE_PLL); + if (!adc3xxx->use_pll) { + snd_soc_dapm_add_routes(dapm, adc3xxx_pll_intercon, + ARRAY_SIZE(adc3xxx_pll_intercon)); + adc3xxx->use_pll = 1; + } + } else { + snd_soc_component_write(component, ADC3XXX_CLKGEN_MUX, ADC3XXX_NO_PLL); + if (adc3xxx->use_pll) { + snd_soc_dapm_del_routes(dapm, adc3xxx_pll_intercon, + ARRAY_SIZE(adc3xxx_pll_intercon)); + adc3xxx->use_pll = 0; + } + } + + /* NADC */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_NADC, + ADC3XXX_NADC_MASK, adc3xxx_divs[i].nadc); + /* MADC */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_MADC, + ADC3XXX_MADC_MASK, adc3xxx_divs[i].madc); + /* AOSR */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_AOSR, + ADC3XXX_AOSR_MASK, adc3xxx_divs[i].aosr); + /* BDIV N Value */ + /* BCLK is (by default) set up to be derived from ADC_CLK */ + bdiv = (adc3xxx_divs[i].aosr * adc3xxx_divs[i].madc) / (2 * width); + snd_soc_component_update_bits(component, ADC3XXX_BCLK_N_DIV, + ADC3XXX_BDIV_MASK, bdiv); + + return 0; +} + +static const char *adc3xxx_pll_mode_text(int pll_mode) +{ + switch (pll_mode) { + case ADC3XXX_PLL_AUTO: + return "PLL auto"; + case ADC3XXX_PLL_ENABLE: + return "PLL enable"; + case ADC3XXX_PLL_BYPASS: + return "PLL bypass"; + default: + break; + } + + return "PLL unknown"; +} + +static int adc3xxx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + int ret; + + ret = adc3xxx_parse_pll_mode(clk_id, &adc3xxx->pll_mode); + if (ret < 0) + return ret; + + adc3xxx->sysclk = freq; + dev_dbg(component->dev, "Set sysclk to %u Hz, %s\n", + freq, adc3xxx_pll_mode_text(adc3xxx->pll_mode)); + return 0; +} + +static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + u8 clkdir = 0, format = 0; + int master = 0; + int ret; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + master = 1; + clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBC_CFC: + master = 0; + break; + default: + dev_err(component->dev, "Invalid DAI clock setup\n"); + return -EINVAL; + } + + /* + * match both interface format and signal polarities since they + * are fixed + */ + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF: + format = ADC3XXX_FORMAT_DSP; + break; + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF: + format = ADC3XXX_FORMAT_DSP; + break; + case SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_RJF; + break; + case SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_LJF; + break; + default: + dev_err(component->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + /* Add/del route enabling BCLK output as applicable */ + if (master && !adc3xxx->master) + snd_soc_dapm_add_routes(dapm, adc3xxx_bclk_out_intercon, + ARRAY_SIZE(adc3xxx_bclk_out_intercon)); + else if (!master && adc3xxx->master) + snd_soc_dapm_del_routes(dapm, adc3xxx_bclk_out_intercon, + ARRAY_SIZE(adc3xxx_bclk_out_intercon)); + adc3xxx->master = master; + + /* set clock direction and format */ + ret = snd_soc_component_update_bits(component, + ADC3XXX_INTERFACE_CTRL_1, + ADC3XXX_CLKDIR_MASK | ADC3XXX_FORMAT_MASK, + clkdir | format); + if (ret < 0) + return ret; + return 0; +} + +static const struct snd_soc_dai_ops adc3xxx_dai_ops = { + .hw_params = adc3xxx_hw_params, + .set_sysclk = adc3xxx_set_dai_sysclk, + .set_fmt = adc3xxx_set_dai_fmt, +}; + +static struct snd_soc_dai_driver adc3xxx_dai = { + .name = "tlv320adc3xxx-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = ADC3XXX_RATES, + .formats = ADC3XXX_FORMATS, + }, + .ops = &adc3xxx_dai_ops, +}; + +static const struct snd_soc_component_driver soc_component_dev_adc3xxx = { + .controls = adc3xxx_snd_controls, + .num_controls = ARRAY_SIZE(adc3xxx_snd_controls), + .dapm_widgets = adc3xxx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adc3xxx_dapm_widgets), + .dapm_routes = adc3xxx_intercon, + .num_dapm_routes = ARRAY_SIZE(adc3xxx_intercon), + .endianness = 1, +}; + +static const struct i2c_device_id adc3xxx_i2c_id[] = { + { "tlv320adc3001", ADC3001 }, + { "tlv320adc3101", ADC3101 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, adc3xxx_i2c_id); + +static int adc3xxx_i2c_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct adc3xxx *adc3xxx = NULL; + const struct i2c_device_id *id; + int ret; + + adc3xxx = devm_kzalloc(dev, sizeof(struct adc3xxx), GFP_KERNEL); + if (!adc3xxx) + return -ENOMEM; + adc3xxx->dev = dev; + + adc3xxx->rst_pin = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(adc3xxx->rst_pin)) { + return dev_err_probe(dev, PTR_ERR(adc3xxx->rst_pin), + "Failed to request rst_pin\n"); + } + + adc3xxx->mclk = devm_clk_get(dev, NULL); + if (IS_ERR(adc3xxx->mclk)) { + /* + * The chip itself supports running off the BCLK either + * directly or via the PLL, but the driver does not (yet), so + * having a specified mclk is required. Otherwise, we could + * use the lack of a clocks property to indicate when BCLK is + * intended as the clock source. + */ + return dev_err_probe(dev, PTR_ERR(adc3xxx->mclk), + "Failed to acquire MCLK\n"); + } else if (adc3xxx->mclk) { + ret = clk_prepare_enable(adc3xxx->mclk); + if (ret < 0) + return ret; + dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk)); + } + + ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]); + if (ret < 0) + goto err_unprepare_mclk; + ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]); + if (ret < 0) + goto err_unprepare_mclk; + ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); + if (ret < 0) + goto err_unprepare_mclk; + ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); + if (ret < 0) + goto err_unprepare_mclk; + + adc3xxx->regmap = devm_regmap_init_i2c(i2c, &adc3xxx_regmap); + if (IS_ERR(adc3xxx->regmap)) { + ret = PTR_ERR(adc3xxx->regmap); + goto err_unprepare_mclk; + } + + i2c_set_clientdata(i2c, adc3xxx); + + id = i2c_match_id(adc3xxx_i2c_id, i2c); + adc3xxx->type = id->driver_data; + + /* Reset codec chip */ + gpiod_set_value_cansleep(adc3xxx->rst_pin, 1); + usleep_range(2000, 100000); /* Requirement: > 10 ns (datasheet p13) */ + gpiod_set_value_cansleep(adc3xxx->rst_pin, 0); + + /* Potentially set up pins used as GPIOs */ + adc3xxx_init_gpio(adc3xxx); + + ret = snd_soc_register_component(dev, + &soc_component_dev_adc3xxx, &adc3xxx_dai, 1); + if (ret < 0) { + dev_err(dev, "Failed to register codec: %d\n", ret); + goto err_unprepare_mclk; + } + + return 0; + +err_unprepare_mclk: + clk_disable_unprepare(adc3xxx->mclk); + return ret; +} + +static void __exit adc3xxx_i2c_remove(struct i2c_client *client) +{ + struct adc3xxx *adc3xxx = i2c_get_clientdata(client); + + if (adc3xxx->mclk) + clk_disable_unprepare(adc3xxx->mclk); + adc3xxx_free_gpio(adc3xxx); + snd_soc_unregister_component(&client->dev); +} + +static const struct of_device_id tlv320adc3xxx_of_match[] = { + { .compatible = "ti,tlv320adc3001", }, + { .compatible = "ti,tlv320adc3101", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tlv320adc3xxx_of_match); + +static struct i2c_driver adc3xxx_i2c_driver = { + .driver = { + .name = "tlv320adc3xxx-codec", + .of_match_table = tlv320adc3xxx_of_match, + }, + .probe_new = adc3xxx_i2c_probe, + .remove = __exit_p(adc3xxx_i2c_remove), + .id_table = adc3xxx_i2c_id, +}; + +module_i2c_driver(adc3xxx_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320ADC3xxx codec driver"); +MODULE_AUTHOR("shahina.s@mistralsolutions.com"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 32b120d624b2..91a22d927915 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -31,9 +31,9 @@ struct adcx140_priv { struct device *dev; bool micbias_vg; + bool phase_calib_on; unsigned int dai_fmt; - unsigned int tdm_delay; unsigned int slot_width; }; @@ -593,6 +593,52 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"MIC4M Input Mux", "Digital", "MIC4M"}, }; +#define ADCX140_PHASE_CALIB_SWITCH(xname) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = adcx140_phase_calib_info, \ + .get = adcx140_phase_calib_get, \ + .put = adcx140_phase_calib_put} + +static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_soc_component *codec = + snd_soc_kcontrol_component(kcontrol); + struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec); + + value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0; + + + return 0; +} + +static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_soc_component *codec + = snd_soc_kcontrol_component(kcontrol); + struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec); + + bool v = value->value.integer.value[0] ? true : false; + + if (adcx140->phase_calib_on != v) { + adcx140->phase_calib_on = v; + return 1; + } + return 0; +} + static const struct snd_kcontrol_new adcx140_snd_controls[] = { SOC_SINGLE_TLV("Analog CH1 Mic Gain Volume", ADCX140_CH1_CFG1, 2, 42, 0, adc_tlv), @@ -629,6 +675,7 @@ static const struct snd_kcontrol_new adcx140_snd_controls[] = { 0, 0xff, 0, dig_vol_tlv), SOC_SINGLE_TLV("Digital CH8 Out Volume", ADCX140_CH8_CFG2, 0, 0xff, 0, dig_vol_tlv), + ADCX140_PHASE_CALIB_SWITCH("Phase Calibration Switch"), }; static int adcx140_reset(struct adcx140_priv *adcx140) @@ -654,6 +701,8 @@ static int adcx140_reset(struct adcx140_priv *adcx140) static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) { int pwr_ctrl = 0; + int ret = 0; + struct snd_soc_component *component = adcx140->component; if (power_state) pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; @@ -661,6 +710,14 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) if (adcx140->micbias_vg && power_state) pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ; + if (pwr_ctrl) { + ret = regmap_write(adcx140->regmap, ADCX140_PHASE_CALIB, + adcx140->phase_calib_on ? 0x00 : 0x40); + if (ret) + dev_err(component->dev, "%s: register write error %d\n", + __func__, ret); + } + regmap_update_bits(adcx140->regmap, ADCX140_PWR_CFG, ADCX140_PWR_CTRL_MSK, pwr_ctrl); } @@ -713,16 +770,14 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, bool inverted_bclk = false; /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } @@ -792,12 +847,13 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); - unsigned int lsb; - /* TDM based on DSP mode requires slots to be adjacent */ - lsb = __ffs(tx_mask); - if ((lsb + 1) != __fls(tx_mask)) { - dev_err(component->dev, "Invalid mask, slots must be adjacent\n"); + /* + * The chip itself supports arbitrary masks, but the driver currently + * only supports adjacent slots beginning at the first slot. + */ + if (tx_mask != GENMASK(__fls(tx_mask), 0)) { + dev_err(component->dev, "Only lower adjacent slots are supported\n"); return -EINVAL; } @@ -812,7 +868,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, return -EINVAL; } - adcx140->tdm_delay = lsb; adcx140->slot_width = slot_width; return 0; @@ -1055,7 +1110,6 @@ static const struct snd_soc_component_driver soc_codec_driver_adcx140 = { .idle_bias_on = 0, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver adcx140_dai_driver[] = { @@ -1083,8 +1137,14 @@ static const struct of_device_id tlv320adcx140_of_match[] = { MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match); #endif -static int adcx140_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static void adcx140_disable_regulator(void *arg) +{ + struct adcx140_priv *adcx140 = arg; + + regulator_disable(adcx140->supply_areg); +} + +static int adcx140_i2c_probe(struct i2c_client *i2c) { struct adcx140_priv *adcx140; int ret; @@ -1093,6 +1153,7 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, if (!adcx140) return -ENOMEM; + adcx140->phase_calib_on = false; adcx140->dev = &i2c->dev; adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev, @@ -1113,6 +1174,10 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, dev_err(adcx140->dev, "Failed to enable areg\n"); return ret; } + + ret = devm_add_action_or_reset(&i2c->dev, adcx140_disable_regulator, adcx140); + if (ret) + return ret; } adcx140->regmap = devm_regmap_init_i2c(i2c, &adcx140_i2c_regmap); @@ -1143,7 +1208,7 @@ static struct i2c_driver adcx140_i2c_driver = { .name = "tlv320adcx140-codec", .of_match_table = of_match_ptr(tlv320adcx140_of_match), }, - .probe = adcx140_i2c_probe, + .probe_new = adcx140_i2c_probe, .id_table = adcx140_i2c_id, }; module_i2c_driver(adcx140_i2c_driver); diff --git a/sound/soc/codecs/tlv320adcx140.h b/sound/soc/codecs/tlv320adcx140.h index d7d4e3a88b5c..fd80fac8b327 100644 --- a/sound/soc/codecs/tlv320adcx140.h +++ b/sound/soc/codecs/tlv320adcx140.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// TLV320ADCX104 Sound driver +// TLV320ADCX140 Sound driver // Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ #ifndef _TLV320ADCX140_H @@ -90,6 +90,7 @@ #define ADCX140_PWR_CFG 0x75 #define ADCX140_DEV_STS0 0x76 #define ADCX140_DEV_STS1 0x77 +#define ADCX140_PHASE_CALIB 0X7b #define ADCX140_RESET BIT(0) diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index dbb8f969274c..1f97673a1cc0 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -16,8 +16,7 @@ #include "tlv320aic23.h" -static int tlv320aic23_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int tlv320aic23_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -48,7 +47,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { .name = "tlv320aic23-codec", .of_match_table = of_match_ptr(tlv320aic23_of_match), }, - .probe = tlv320aic23_i2c_probe, + .probe_new = tlv320aic23_i2c_probe, .id_table = tlv320aic23_id, }; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 2400093e2c99..c47aa4d4162d 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -429,12 +429,11 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg |= TLV320AIC23_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface_reg &= ~TLV320AIC23_MS_MASTER; break; default: @@ -587,7 +586,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; int tlv320aic23_probe(struct device *dev, struct regmap *regmap) diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 077415a57225..e5dfb3d752a3 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -32,7 +32,7 @@ struct aic26 { struct spi_device *spi; struct regmap *regmap; struct snd_soc_component *component; - int master; + int clock_provider; int datfm; int mclk; @@ -117,8 +117,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream, reg = dval << 2; snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg); - /* Audio Control 3 (master mode, fsref rate) */ - if (aic26->master) + /* Audio Control 3 (clock provider mode, fsref rate) */ + if (aic26->clock_provider) reg = 0x0800; if (fsref == 48000) reg = 0x2000; @@ -178,10 +178,9 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n", codec_dai, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic26->clock_provider = 1; break; + case SND_SOC_DAIFMT_CBC_CFC: aic26->clock_provider = 0; break; default: dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL; } @@ -272,7 +271,7 @@ static ssize_t keyclick_show(struct device *dev, freq = (125 << ((val >> 8) & 0x7)) >> 1; len = 2 * (1 + ((val >> 4) & 0xf)); - return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); + return sysfs_emit(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); } /* Any write to the keyclick attribute will trigger the keyclick event */ @@ -332,7 +331,6 @@ static const struct snd_soc_component_driver aic26_soc_component_dev = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config aic26_regmap = { @@ -363,7 +361,7 @@ static int aic26_spi_probe(struct spi_device *spi) /* Initialize the driver data */ aic26->spi = spi; dev_set_drvdata(&spi->dev, aic26); - aic26->master = 1; + aic26->clock_provider = 1; ret = devm_snd_soc_register_component(&spi->dev, &aic26_soc_component_dev, &aic26_dai, 1); diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h index 1f2879b7a080..c86569883e0c 100644 --- a/sound/soc/codecs/tlv320aic26.h +++ b/sound/soc/codecs/tlv320aic26.h @@ -6,8 +6,8 @@ * Copyright (C) 2008 Secret Lab Technologies Ltd. */ -#ifndef _TLV320AIC16_H_ -#define _TLV320AIC16_H_ +#ifndef _TLV320AIC26_H_ +#define _TLV320AIC26_H_ /* AIC26 Registers */ #define AIC26_PAGE_ADDR(page, offset) ((page << 11) | offset << 5) @@ -88,4 +88,4 @@ enum aic26_wlen { AIC26_WLEN_32 = 3 << 10, }; -#endif /* _TLV320AIC16_H_ */ +#endif /* _TLV320AIC26_H_ */ diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 52d2c968b5c0..0847302121f6 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> @@ -31,7 +32,7 @@ #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> -#include <dt-bindings/sound/tlv320aic31xx-micbias.h> +#include <dt-bindings/sound/tlv320aic31xx.h> #include "tlv320aic31xx.h" @@ -169,6 +170,7 @@ struct aic31xx_priv { struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; struct snd_soc_jack *jack; + u32 sysclk_id; unsigned int sysclk; u8 p_div; int rate_div_line; @@ -180,6 +182,7 @@ struct aic31xx_priv { struct aic31xx_rate_divs { u32 mclk_p; u32 rate; + u8 pll_r; u8 pll_j; u16 pll_d; u16 dosr; @@ -192,51 +195,71 @@ struct aic31xx_rate_divs { /* ADC dividers can be disabled by configuring them to 0 */ static const struct aic31xx_rate_divs aic31xx_divs[] = { - /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ + /* mclk/p rate pll: r j d dosr ndac mdac aors nadc madc */ /* 8k rate */ - {12000000, 8000, 8, 1920, 128, 48, 2, 128, 48, 2}, - {12000000, 8000, 8, 1920, 128, 32, 3, 128, 32, 3}, - {12500000, 8000, 7, 8643, 128, 48, 2, 128, 48, 2}, + { 512000, 8000, 4, 48, 0, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, + {12500000, 8000, 1, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ - {12000000, 11025, 7, 5264, 128, 32, 2, 128, 32, 2}, - {12000000, 11025, 8, 4672, 128, 24, 3, 128, 24, 3}, - {12500000, 11025, 7, 2253, 128, 32, 2, 128, 32, 2}, + { 705600, 11025, 3, 48, 0, 128, 24, 3, 128, 24, 3}, + {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, + {12500000, 11025, 1, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ - {12000000, 16000, 8, 1920, 128, 24, 2, 128, 24, 2}, - {12000000, 16000, 8, 1920, 128, 16, 3, 128, 16, 3}, - {12500000, 16000, 7, 8643, 128, 24, 2, 128, 24, 2}, + { 512000, 16000, 4, 48, 0, 128, 16, 3, 128, 16, 3}, + { 1024000, 16000, 2, 48, 0, 128, 16, 3, 128, 16, 3}, + {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, + {12500000, 16000, 1, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ - {12000000, 22050, 7, 5264, 128, 16, 2, 128, 16, 2}, - {12000000, 22050, 8, 4672, 128, 12, 3, 128, 12, 3}, - {12500000, 22050, 7, 2253, 128, 16, 2, 128, 16, 2}, + { 705600, 22050, 4, 36, 0, 128, 12, 3, 128, 12, 3}, + { 1411200, 22050, 2, 36, 0, 128, 12, 3, 128, 12, 3}, + {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, + {12500000, 22050, 1, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ - {12000000, 32000, 8, 1920, 128, 12, 2, 128, 12, 2}, - {12000000, 32000, 8, 1920, 128, 8, 3, 128, 8, 3}, - {12500000, 32000, 7, 8643, 128, 12, 2, 128, 12, 2}, + { 1024000, 32000, 2, 48, 0, 128, 12, 2, 128, 12, 2}, + { 2048000, 32000, 1, 48, 0, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, + {12500000, 32000, 1, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ - {12000000, 44100, 7, 5264, 128, 8, 2, 128, 8, 2}, - {12000000, 44100, 8, 4672, 128, 6, 3, 128, 6, 3}, - {12500000, 44100, 7, 2253, 128, 8, 2, 128, 8, 2}, + { 1411200, 44100, 2, 32, 0, 128, 8, 2, 128, 8, 2}, + { 2822400, 44100, 1, 32, 0, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, + {12500000, 44100, 1, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ - {12000000, 48000, 8, 1920, 128, 8, 2, 128, 8, 2}, - {12000000, 48000, 7, 6800, 96, 5, 4, 96, 5, 4}, - {12500000, 48000, 7, 8643, 128, 8, 2, 128, 8, 2}, + { 1536000, 48000, 2, 32, 0, 128, 8, 2, 128, 8, 2}, + { 3072000, 48000, 1, 32, 0, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, + {12500000, 48000, 1, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ - {12000000, 88200, 7, 5264, 64, 8, 2, 64, 8, 2}, - {12000000, 88200, 8, 4672, 64, 6, 3, 64, 6, 3}, - {12500000, 88200, 7, 2253, 64, 8, 2, 64, 8, 2}, + { 2822400, 88200, 2, 16, 0, 64, 8, 2, 64, 8, 2}, + { 5644800, 88200, 1, 16, 0, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, + {12500000, 88200, 1, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ - {12000000, 96000, 8, 1920, 64, 8, 2, 64, 8, 2}, - {12000000, 96000, 7, 6800, 48, 5, 4, 48, 5, 4}, - {12500000, 96000, 7, 8643, 64, 8, 2, 64, 8, 2}, + { 3072000, 96000, 2, 16, 0, 64, 8, 2, 64, 8, 2}, + { 6144000, 96000, 1, 16, 0, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, + {12500000, 96000, 1, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ - {12000000, 176400, 7, 5264, 32, 8, 2, 32, 8, 2}, - {12000000, 176400, 8, 4672, 32, 6, 3, 32, 6, 3}, - {12500000, 176400, 7, 2253, 32, 8, 2, 32, 8, 2}, + { 5644800, 176400, 2, 8, 0, 32, 8, 2, 32, 8, 2}, + {11289600, 176400, 1, 8, 0, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, + {12500000, 176400, 1, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ - {12000000, 192000, 8, 1920, 32, 8, 2, 32, 8, 2}, - {12000000, 192000, 7, 6800, 24, 5, 4, 24, 5, 4}, - {12500000, 192000, 7, 8643, 32, 8, 2, 32, 8, 2}, + { 6144000, 192000, 2, 8, 0, 32, 8, 2, 32, 8, 2}, + {12288000, 192000, 1, 8, 0, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, + {12500000, 192000, 1, 7, 8643, 32, 8, 2, 32, 8, 2}, }; static const char * const ldac_in_text[] = { @@ -888,7 +911,7 @@ static int aic31xx_setup_pll(struct snd_soc_component *component, /* PLL configuration */ snd_soc_component_update_bits(component, AIC31XX_PLLPR, AIC31XX_PLL_MASK, - (aic31xx->p_div << 4) | 0x01); + (aic31xx->p_div << 4) | aic31xx_divs[i].pll_r); snd_soc_component_write(component, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); snd_soc_component_write(component, AIC31XX_PLLDMSB, @@ -941,6 +964,7 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); u8 data = 0; dev_dbg(component->dev, "## %s: width %d rate %d\n", @@ -972,6 +996,16 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream, AIC31XX_IFACE1_DATALEN_MASK, data); + /* + * If BCLK is used as PLL input, the sysclk is determined by the hw + * params. So it must be updated here to match the input frequency. + */ + if (aic31xx->sysclk_id == AIC31XX_PLL_CLKIN_BCLK) { + aic31xx->sysclk = params_rate(params) * params_width(params) * + params_channels(params); + aic31xx->p_div = 1; + } + return aic31xx_setup_pll(component, params); } @@ -999,8 +1033,8 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); int ret; - fmt &= SND_SOC_DAIFMT_MASTER_MASK; - if (fmt == SND_SOC_DAIFMT_CBS_CFS && + fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + if (fmt == SND_SOC_DAIFMT_CBC_CFC && aic31xx->master_dapm_route_applied) { /* * Remove the DAPM route(s) for codec clock master modes, @@ -1017,7 +1051,7 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component, return ret; aic31xx->master_dapm_route_applied = false; - } else if (fmt != SND_SOC_DAIFMT_CBS_CFS && + } else if (fmt != SND_SOC_DAIFMT_CBC_CFC && !aic31xx->master_dapm_route_applied) { /* * Add the needed DAPM route(s) for codec clock master modes, @@ -1049,21 +1083,20 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: iface_reg1 |= AIC31XX_WCLK_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: iface_reg1 |= AIC31XX_BCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(component->dev, "Invalid DAI master/slave interface\n"); + dev_err(component->dev, "Invalid DAI clock provider\n"); return -EINVAL; } @@ -1156,6 +1189,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, snd_soc_component_update_bits(component, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK, clk_id << AIC31XX_PLL_CLKIN_SHIFT); + aic31xx->sysclk_id = clk_id; aic31xx->sysclk = freq; return 0; @@ -1383,7 +1417,6 @@ static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops aic31xx_dai_ops = { @@ -1593,11 +1626,24 @@ static void aic31xx_configure_ocmv(struct aic31xx_priv *priv) } } -static int aic31xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id aic31xx_i2c_id[] = { + { "tlv320aic310x", AIC3100 }, + { "tlv320aic311x", AIC3110 }, + { "tlv320aic3100", AIC3100 }, + { "tlv320aic3110", AIC3110 }, + { "tlv320aic3120", AIC3120 }, + { "tlv320aic3111", AIC3111 }, + { "tlv320dac3100", DAC3100 }, + { "tlv320dac3101", DAC3101 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); + +static int aic31xx_i2c_probe(struct i2c_client *i2c) { struct aic31xx_priv *aic31xx; unsigned int micbias_value = MICBIAS_2_0V; + const struct i2c_device_id *id = i2c_match_id(aic31xx_i2c_id, i2c); int i, ret; dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, @@ -1645,11 +1691,9 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(aic31xx->gpio_reset)) { - if (PTR_ERR(aic31xx->gpio_reset) != -EPROBE_DEFER) - dev_err(aic31xx->dev, "not able to acquire gpio\n"); - return PTR_ERR(aic31xx->gpio_reset); - } + if (IS_ERR(aic31xx->gpio_reset)) + return dev_err_probe(aic31xx->dev, PTR_ERR(aic31xx->gpio_reset), + "not able to acquire gpio\n"); for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) aic31xx->supplies[i].supply = aic31xx_supply_names[i]; @@ -1657,12 +1701,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ret = devm_regulator_bulk_get(aic31xx->dev, ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(aic31xx->dev, - "Failed to request supplies: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(aic31xx->dev, ret, "Failed to request supplies\n"); aic31xx_configure_ocmv(aic31xx); @@ -1700,26 +1740,13 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ARRAY_SIZE(aic31xx_dai_driver)); } -static const struct i2c_device_id aic31xx_i2c_id[] = { - { "tlv320aic310x", AIC3100 }, - { "tlv320aic311x", AIC3110 }, - { "tlv320aic3100", AIC3100 }, - { "tlv320aic3110", AIC3110 }, - { "tlv320aic3120", AIC3120 }, - { "tlv320aic3111", AIC3111 }, - { "tlv320dac3100", DAC3100 }, - { "tlv320dac3101", DAC3101 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); - static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", .of_match_table = of_match_ptr(tlv320aic31xx_of_match), .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), }, - .probe = aic31xx_i2c_probe, + .probe_new = aic31xx_i2c_probe, .id_table = aic31xx_i2c_id, }; module_i2c_driver(aic31xx_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 2513922a0292..80d062578fb5 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -118,7 +118,7 @@ struct aic31xx_pdata { #define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2) #define AIC31XX_PLL_CLKIN_SHIFT (2) #define AIC31XX_PLL_CLKIN_MCLK 0x00 -#define AIC31XX_PLL_CLKIN_BCKL 0x01 +#define AIC31XX_PLL_CLKIN_BCLK 0x01 #define AIC31XX_PLL_CLKIN_GPIO1 0x02 #define AIC31XX_PLL_CLKIN_DIN 0x03 #define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0) diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index ed70e3d9baf2..d1e543ca3521 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -17,9 +17,9 @@ #include "tlv320aic32x4.h" static const struct of_device_id aic32x4_of_id[]; +static const struct i2c_device_id aic32x4_i2c_id[]; -static int aic32x4_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int aic32x4_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config; @@ -35,18 +35,19 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, oid = of_match_node(aic32x4_of_id, i2c->dev.of_node); dev_set_drvdata(&i2c->dev, (void *)oid->data); - } else if (id) { + } else { + const struct i2c_device_id *id; + + id = i2c_match_id(aic32x4_i2c_id, i2c); dev_set_drvdata(&i2c->dev, (void *)id->driver_data); } return aic32x4_probe(&i2c->dev, regmap); } -static int aic32x4_i2c_remove(struct i2c_client *i2c) +static void aic32x4_i2c_remove(struct i2c_client *i2c) { aic32x4_remove(&i2c->dev); - - return 0; } static const struct i2c_device_id aic32x4_i2c_id[] = { @@ -70,7 +71,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .name = "tlv320aic32x4", .of_match_table = aic32x4_of_id, }, - .probe = aic32x4_i2c_probe, + .probe_new = aic32x4_i2c_probe, .remove = aic32x4_i2c_remove, .id_table = aic32x4_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index a8958cd1c692..03cce8d6404f 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -46,11 +46,9 @@ static int aic32x4_spi_probe(struct spi_device *spi) return aic32x4_probe(&spi->dev, regmap); } -static int aic32x4_spi_remove(struct spi_device *spi) +static void aic32x4_spi_remove(struct spi_device *spi) { aic32x4_remove(&spi->dev); - - return 0; } static const struct spi_device_id aic32x4_spi_id[] = { diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 8f42fd7bc053..ffe1828a4b7e 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -49,6 +49,8 @@ struct aic32x4_priv { struct aic32x4_setup_data *setup; struct device *dev; enum aic32x4_type type; + + unsigned int fmt; }; static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, @@ -611,19 +613,19 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; + struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); u8 iface_reg_1 = 0; u8 iface_reg_2 = 0; u8 iface_reg_3 = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: - printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n"); + printk(KERN_ERR "aic32x4: invalid clock provider\n"); return -EINVAL; } @@ -654,6 +656,8 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } + aic32x4->fmt = fmt; + snd_soc_component_update_bits(component, AIC32X4_IFACE1, AIC32X4_IFACE1_DATATYPE_MASK | AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); @@ -758,6 +762,10 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, return -EINVAL; } + /* PCM over I2S is always 2-channel */ + if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) + channels = 2; + madc = DIV_ROUND_UP((32 * adc_resource_class), aosr); max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) * dosr_increment; @@ -1078,7 +1086,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { @@ -1200,7 +1207,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c index 2f272bc3f5da..d7e94d564dbf 100644 --- a/sound/soc/codecs/tlv320aic3x-i2c.c +++ b/sound/soc/codecs/tlv320aic3x-i2c.c @@ -17,10 +17,21 @@ #include "tlv320aic3x.h" -static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static const struct i2c_device_id aic3x_i2c_id[] = { + { "tlv320aic3x", AIC3X_MODEL_3X }, + { "tlv320aic33", AIC3X_MODEL_33 }, + { "tlv320aic3007", AIC3X_MODEL_3007 }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, + { "tlv320aic3106", AIC3X_MODEL_3106 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); + +static int aic3x_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; struct regmap_config config; + const struct i2c_device_id *id = i2c_match_id(aic3x_i2c_id, i2c); config = aic3x_regmap; config.reg_bits = 8; @@ -30,23 +41,11 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i return aic3x_probe(&i2c->dev, regmap, id->driver_data); } -static int aic3x_i2c_remove(struct i2c_client *i2c) +static void aic3x_i2c_remove(struct i2c_client *i2c) { aic3x_remove(&i2c->dev); - - return 0; } -static const struct i2c_device_id aic3x_i2c_id[] = { - { "tlv320aic3x", AIC3X_MODEL_3X }, - { "tlv320aic33", AIC3X_MODEL_33 }, - { "tlv320aic3007", AIC3X_MODEL_3007 }, - { "tlv320aic3104", AIC3X_MODEL_3104 }, - { "tlv320aic3106", AIC3X_MODEL_3106 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); - static const struct of_device_id aic3x_of_id[] = { { .compatible = "ti,tlv320aic3x", }, { .compatible = "ti,tlv320aic33" }, @@ -62,7 +61,7 @@ static struct i2c_driver aic3x_i2c_driver = { .name = "tlv320aic3x", .of_match_table = aic3x_of_id, }, - .probe = aic3x_i2c_probe, + .probe_new = aic3x_i2c_probe, .remove = aic3x_i2c_remove, .id_table = aic3x_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c index 494e84402232..deed6ec7e081 100644 --- a/sound/soc/codecs/tlv320aic3x-spi.c +++ b/sound/soc/codecs/tlv320aic3x-spi.c @@ -35,11 +35,9 @@ static int aic3x_spi_probe(struct spi_device *spi) return aic3x_probe(&spi->dev, regmap, id->driver_data); } -static int aic3x_spi_remove(struct spi_device *spi) +static void aic3x_spi_remove(struct spi_device *spi) { aic3x_remove(&spi->dev); - - return 0; } static const struct spi_device_id aic3x_spi_id[] = { diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index d53037b1509d..08938801daec 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1253,22 +1253,21 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aic3x->master = 0; iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aic3x->master = 1; iface_areg |= BIT_CLK_MASTER; iface_areg &= ~WORD_CLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aic3x->master = 1; iface_areg |= WORD_CLK_MASTER; iface_areg &= ~BIT_CLK_MASTER; @@ -1698,7 +1697,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic3x = { .num_dapm_routes = ARRAY_SIZE(intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 48572d66cb3b..16ce3ef1134b 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1317,16 +1317,14 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A); aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B); - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* Codec Master */ + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK); break; - case SND_SOC_DAIFMT_CBS_CFS: - /* Codec Slave */ + case SND_SOC_DAIFMT_CBC_CFC: if (dac33->fifo_mode) { - dev_err(component->dev, "FIFO mode requires master mode\n"); + dev_err(component->dev, "FIFO mode requires provider mode\n"); return -EINVAL; } else aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); @@ -1433,7 +1431,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = { .num_dapm_routes = ARRAY_SIZE(audio_map), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define DAC33_RATES (SNDRV_PCM_RATE_44100 | \ @@ -1463,8 +1460,7 @@ static struct snd_soc_dai_driver dac33_dai = { .ops = &dac33_dai_ops, }; -static int dac33_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int dac33_i2c_probe(struct i2c_client *client) { struct tlv320dac33_platform_data *pdata; struct tlv320dac33_priv *dac33; @@ -1540,7 +1536,7 @@ err_gpio: return ret; } -static int dac33_i2c_remove(struct i2c_client *client) +static void dac33_i2c_remove(struct i2c_client *client) { struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client); @@ -1549,8 +1545,6 @@ static int dac33_i2c_remove(struct i2c_client *client) if (dac33->power_gpio >= 0) gpio_free(dac33->power_gpio); - - return 0; } static const struct i2c_device_id tlv320dac33_i2c_id[] = { @@ -1566,7 +1560,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .driver = { .name = "tlv320dac33-codec", }, - .probe = dac33_i2c_probe, + .probe_new = dac33_i2c_probe, .remove = dac33_i2c_remove, .id_table = tlv320dac33_i2c_id, }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index e2d7ae615c52..8c00db32996b 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -209,13 +209,20 @@ static const struct regmap_config tpa6130a2_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int tpa6130a2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id tpa6130a2_id[] = { + { "tpa6130a2", TPA6130A2 }, + { "tpa6140a2", TPA6140A2 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); + +static int tpa6130a2_probe(struct i2c_client *client) { struct device *dev; struct tpa6130a2_data *data; struct tpa6130a2_platform_data *pdata = client->dev.platform_data; struct device_node *np = client->dev.of_node; + const struct i2c_device_id *id; const char *regulator; unsigned int version; int ret; @@ -244,6 +251,7 @@ static int tpa6130a2_probe(struct i2c_client *client, i2c_set_clientdata(client, data); + id = i2c_match_id(tpa6130a2_id, client); data->id = id->driver_data; if (data->power_gpio >= 0) { @@ -297,13 +305,6 @@ static int tpa6130a2_probe(struct i2c_client *client, &tpa6130a2_component_driver, NULL, 0); } -static const struct i2c_device_id tpa6130a2_id[] = { - { "tpa6130a2", TPA6130A2 }, - { "tpa6140a2", TPA6140A2 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); - #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tpa6130a2_of_match[] = { { .compatible = "ti,tpa6130a2", }, @@ -318,7 +319,7 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .name = "tpa6130a2", .of_match_table = of_match_ptr(tpa6130a2_of_match), }, - .probe = tpa6130a2_probe, + .probe_new = tpa6130a2_probe, .id_table = tpa6130a2_id, }; diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 962f5d48378a..2305a472d132 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -78,12 +78,20 @@ static const int ts3a227e_buttons[] = { #define ADC_COMPLETE_INT_DISABLE 0x04 #define INTB_DISABLE 0x08 +/* TS3A227E_REG_SETTING_1 0x4 */ +#define DEBOUNCE_INSERTION_SETTING_SFT (0) +#define DEBOUNCE_INSERTION_SETTING_MASK (0x7 << DEBOUNCE_PRESS_SETTING_SFT) + /* TS3A227E_REG_SETTING_2 0x05 */ #define KP_ENABLE 0x04 /* TS3A227E_REG_SETTING_3 0x06 */ -#define MICBIAS_SETTING_SFT (3) +#define MICBIAS_SETTING_SFT 3 #define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT) +#define DEBOUNCE_RELEASE_SETTING_SFT 2 +#define DEBOUNCE_RELEASE_SETTING_MASK (0x1 << DEBOUNCE_RELEASE_SETTING_SFT) +#define DEBOUNCE_PRESS_SETTING_SFT 0 +#define DEBOUNCE_PRESS_SETTING_MASK (0x3 << DEBOUNCE_PRESS_SETTING_SFT) /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ #define TYPE_3_POLE 0x01 @@ -136,7 +144,7 @@ static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: - case TS3A227E_REG_SETTING_2: + case TS3A227E_REG_SETTING_1 ... TS3A227E_REG_SETTING_2: case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: return true; default: @@ -269,21 +277,61 @@ static const struct regmap_config ts3a227e_regmap_config = { static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e, struct device *dev) { - u32 micbias; + u32 value; + u32 value_ms; + u32 setting3_value = 0; + u32 setting3_mask = 0; int err; - err = device_property_read_u32(dev, "ti,micbias", &micbias); + err = device_property_read_u32(dev, "ti,micbias", &value); + if (!err) { + setting3_mask = MICBIAS_SETTING_MASK; + setting3_value = (value << MICBIAS_SETTING_SFT) & + MICBIAS_SETTING_MASK; + } + + err = device_property_read_u32(dev, "ti,debounce-release-ms", + &value_ms); if (!err) { + value = (value_ms > 10); + setting3_mask |= DEBOUNCE_RELEASE_SETTING_MASK; + setting3_value |= (value << DEBOUNCE_RELEASE_SETTING_SFT) & + DEBOUNCE_RELEASE_SETTING_MASK; + } + + err = device_property_read_u32(dev, "ti,debounce-press-ms", &value_ms); + if (!err) { + value = (value_ms + 20) / 40; + if (value > 3) + value = 3; + setting3_mask |= DEBOUNCE_PRESS_SETTING_MASK; + setting3_value |= (value << DEBOUNCE_PRESS_SETTING_SFT) & + DEBOUNCE_PRESS_SETTING_MASK; + } + + if (setting3_mask) regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, - MICBIAS_SETTING_MASK, - (micbias & 0x07) << MICBIAS_SETTING_SFT); + setting3_mask, setting3_value); + + err = device_property_read_u32(dev, "ti,debounce-insertion-ms", + &value_ms); + if (!err) { + if (value_ms < 165) + value = (value_ms + 15) / 30; + else if (value_ms < 1500) + value = 6; + else + value = 7; + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_1, + DEBOUNCE_INSERTION_SETTING_MASK, + (value << DEBOUNCE_INSERTION_SETTING_SFT) & + DEBOUNCE_INSERTION_SETTING_MASK); } return 0; } -static int ts3a227e_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ts3a227e_i2c_probe(struct i2c_client *i2c) { struct ts3a227e *ts3a227e; struct device *dev = &i2c->dev; @@ -389,7 +437,7 @@ static struct i2c_driver ts3a227e_driver = { .of_match_table = of_match_ptr(ts3a227e_of_match), .acpi_match_table = ACPI_PTR(ts3a227e_acpi_match), }, - .probe = ts3a227e_i2c_probe, + .probe_new = ts3a227e_i2c_probe, .id_table = ts3a227e_i2c_ids, }; module_i2c_driver(ts3a227e_driver); diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index fb861baf50e8..fa0c525189c2 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -1197,9 +1197,9 @@ static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; int ret; - /* Slave mode not supported since it needs always-on frame clock */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* Consumer mode not supported since it needs always-on frame clock */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_MS, RV_AIC1_MS_MASTER); if (ret < 0) { @@ -1358,7 +1358,6 @@ static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx) @@ -1409,8 +1408,7 @@ static const struct reg_sequence tscs42xx_patch[] = { static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = { "xtal", "mclk1", "mclk2"}; -static int tscs42xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tscs42xx_i2c_probe(struct i2c_client *i2c) { struct tscs42xx *tscs42xx; int src; @@ -1505,7 +1503,7 @@ static struct i2c_driver tscs42xx_i2c_driver = { .name = "tscs42xx", .of_match_table = tscs42xx_of_match, }, - .probe = tscs42xx_i2c_probe, + .probe_new = tscs42xx_i2c_probe, .id_table = tscs42xx_i2c_id, }; diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 43220bb36701..38622bc247fc 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -57,7 +57,7 @@ struct internal_rate { struct aif { unsigned int id; - bool master; + bool provider; struct pll *pll; }; @@ -756,8 +756,8 @@ static int pll_power_event(struct snd_soc_dapm_widget *w, return 0; } -static inline int aif_set_master(struct snd_soc_component *component, - unsigned int aif_id, bool master) +static inline int aif_set_provider(struct snd_soc_component *component, + unsigned int aif_id, bool provider) { unsigned int reg; unsigned int mask; @@ -780,12 +780,12 @@ static inline int aif_set_master(struct snd_soc_component *component, return ret; } mask = FM_I2SPCTL_PORTMS; - val = master ? FV_PORTMS_MASTER : FV_PORTMS_SLAVE; + val = provider ? FV_PORTMS_MASTER : FV_PORTMS_SLAVE; ret = snd_soc_component_update_bits(component, reg, mask, val); if (ret < 0) { dev_err(component->dev, "Failed to set DAI %d to %s (%d)\n", - aif_id, master ? "master" : "slave", ret); + aif_id, provider ? "provider" : "consumer", ret); return ret; } @@ -797,7 +797,7 @@ int aif_prepare(struct snd_soc_component *component, struct aif *aif) { int ret; - ret = aif_set_master(component, aif->id, aif->master); + ret = aif_set_provider(component, aif->id, aif->provider); if (ret < 0) return ret; @@ -820,7 +820,7 @@ static inline int aif_free(struct snd_soc_component *component, if (!aif_active(&tscs454->aifs_status, aif->id)) { /* Do config in slave mode */ - aif_set_master(component, aif->id, false); + aif_set_provider(component, aif->id, false); dev_dbg(component->dev, "Freeing pll %d from aif %d\n", aif->pll->id, aif->id); free_pll(aif->pll); @@ -2708,17 +2708,17 @@ static int tscs454_set_bclk_ratio(struct snd_soc_dai *dai, return 0; } -static inline int set_aif_master_from_fmt(struct snd_soc_component *component, +static inline int set_aif_provider_from_fmt(struct snd_soc_component *component, struct aif *aif, unsigned int fmt) { int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - aif->master = true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + aif->provider = true; break; - case SND_SOC_DAIFMT_CBS_CFS: - aif->master = false; + case SND_SOC_DAIFMT_CBC_CFC: + aif->provider = false; break; default: ret = -EINVAL; @@ -2888,7 +2888,7 @@ static int tscs454_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct aif *aif = &tscs454->aifs[dai->id]; int ret; - ret = set_aif_master_from_fmt(component, aif, fmt); + ret = set_aif_provider_from_fmt(component, aif, fmt); if (ret < 0) return ret; @@ -3120,18 +3120,17 @@ static int set_aif_sample_format(struct snd_soc_component *component, unsigned int width; int ret; - switch (format) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (snd_pcm_format_width(format)) { + case 16: width = FV_WL_16; break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: width = FV_WL_20; break; - case SNDRV_PCM_FORMAT_S24_3LE: + case 24: width = FV_WL_24; break; - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S32_LE: + case 32: width = FV_WL_32; break; default: @@ -3326,6 +3325,7 @@ static const struct snd_soc_component_driver soc_component_dev_tscs454 = { .num_dapm_routes = ARRAY_SIZE(tscs454_intercon), .controls = tscs454_snd_controls, .num_controls = ARRAY_SIZE(tscs454_snd_controls), + .endianness = 1, }; #define TSCS454_RATES SNDRV_PCM_RATE_8000_96000 @@ -3400,8 +3400,7 @@ static struct snd_soc_dai_driver tscs454_dais[] = { static char const * const src_names[] = { "xtal", "mclk1", "mclk2", "bclk"}; -static int tscs454_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tscs454_i2c_probe(struct i2c_client *i2c) { struct tscs454 *tscs454; int src; @@ -3474,7 +3473,7 @@ static struct i2c_driver tscs454_i2c_driver = { .name = "tscs454", .of_match_table = tscs454_of_match, }, - .probe = tscs454_i2c_probe, + .probe_new = tscs454_i2c_probe, .id_table = tscs454_i2c_id, }; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index e059711ff293..e48768233e20 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -34,6 +34,14 @@ #define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) +struct twl4030_board_params { + unsigned int digimic_delay; /* in ms */ + unsigned int ramp_delay_value; + unsigned int offset_cncl_path; + unsigned int hs_extmute:1; + int hs_extmute_gpio; +}; + /* codec private data */ struct twl4030_priv { unsigned int codec_powered; @@ -58,7 +66,7 @@ struct twl4030_priv { u8 carkitl_enabled, carkitr_enabled; u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1]; - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; }; static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) @@ -193,73 +201,71 @@ static void twl4030_codec_enable(struct snd_soc_component *component, int enable udelay(10); } -static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, - struct device_node *node) +static void +twl4030_get_board_param_values(struct twl4030_board_params *board_params, + struct device_node *node) { int value; - of_property_read_u32(node, "ti,digimic_delay", - &pdata->digimic_delay); - of_property_read_u32(node, "ti,ramp_delay_value", - &pdata->ramp_delay_value); - of_property_read_u32(node, "ti,offset_cncl_path", - &pdata->offset_cncl_path); + of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay); + of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value); + of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path); if (!of_property_read_u32(node, "ti,hs_extmute", &value)) - pdata->hs_extmute = value; + board_params->hs_extmute = value; - pdata->hs_extmute_gpio = of_get_named_gpio(node, - "ti,hs_extmute_gpio", 0); - if (gpio_is_valid(pdata->hs_extmute_gpio)) - pdata->hs_extmute = 1; + board_params->hs_extmute_gpio = of_get_named_gpio(node, "ti,hs_extmute_gpio", 0); + if (gpio_is_valid(board_params->hs_extmute_gpio)) + board_params->hs_extmute = 1; } -static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component) +static struct twl4030_board_params* +twl4030_get_board_params(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata = dev_get_platdata(component->dev); + struct twl4030_board_params *board_params = NULL; struct device_node *twl4030_codec_node = NULL; twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node, "codec"); - if (!pdata && twl4030_codec_node) { - pdata = devm_kzalloc(component->dev, - sizeof(struct twl4030_codec_data), - GFP_KERNEL); - if (!pdata) { + if (twl4030_codec_node) { + board_params = devm_kzalloc(component->dev, + sizeof(struct twl4030_board_params), + GFP_KERNEL); + if (!board_params) { of_node_put(twl4030_codec_node); return NULL; } - twl4030_setup_pdata_of(pdata, twl4030_codec_node); + twl4030_get_board_param_values(board_params, twl4030_codec_node); of_node_put(twl4030_codec_node); } - return pdata; + return board_params; } static void twl4030_init_chip(struct snd_soc_component *component) { - struct twl4030_codec_data *pdata; + struct twl4030_board_params *board_params; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); u8 reg, byte; int i = 0; - pdata = twl4030_get_pdata(component); + board_params = twl4030_get_board_params(component); - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { int ret; - if (!pdata->hs_extmute_gpio) + if (!board_params->hs_extmute_gpio) dev_warn(component->dev, "Extmute GPIO is 0 is this correct?\n"); - ret = gpio_request_one(pdata->hs_extmute_gpio, + ret = gpio_request_one(board_params->hs_extmute_gpio, GPIOF_OUT_INIT_LOW, "hs_extmute"); if (ret) { dev_err(component->dev, "Failed to get hs_extmute GPIO\n"); - pdata->hs_extmute_gpio = -1; + board_params->hs_extmute_gpio = -1; } } else { u8 pin_mux; @@ -290,14 +296,14 @@ static void twl4030_init_chip(struct snd_soc_component *component) twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32); /* Machine dependent setup */ - if (!pdata) + if (!board_params) return; - twl4030->pdata = pdata; + twl4030->board_params = board_params; reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET); reg &= ~TWL4030_RAMP_DELAY; - reg |= (pdata->ramp_delay_value << 2); + reg |= (board_params->ramp_delay_value << 2); twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg); /* initiate offset cancellation */ @@ -305,7 +311,7 @@ static void twl4030_init_chip(struct snd_soc_component *component) reg = twl4030_read(component, TWL4030_REG_ANAMICL); reg &= ~TWL4030_OFFSET_CNCL_SEL; - reg |= pdata->offset_cncl_path; + reg |= board_params->offset_cncl_path; twl4030_write(component, TWL4030_REG_ANAMICL, reg | TWL4030_CNCL_OFFSET_START); @@ -692,7 +698,7 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) { unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; /* Base values for ramp delay calculation: 2^19 - 2^26 */ unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864}; @@ -705,9 +711,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) /* Enable external mute control, this dramatically reduces * the pop-noise */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 1); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 1); } else { hs_pop |= TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -741,9 +747,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp) } /* Disable external mute */ - if (pdata && pdata->hs_extmute) { - if (gpio_is_valid(pdata->hs_extmute_gpio)) { - gpio_set_value(pdata->hs_extmute_gpio, 0); + if (board_params && board_params->hs_extmute) { + if (gpio_is_valid(board_params->hs_extmute_gpio)) { + gpio_set_value(board_params->hs_extmute_gpio, 0); } else { hs_pop &= ~TWL4030_EXTMUTE; twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -806,10 +812,10 @@ static int digimic_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->digimic_delay) - twl4030_wait_ms(pdata->digimic_delay); + if (board_params && board_params->digimic_delay) + twl4030_wait_ms(board_params->digimic_delay); return 0; } @@ -1840,13 +1846,12 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF); format = old_format; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: format &= ~(TWL4030_AIF_SLAVE_EN); format &= ~(TWL4030_CLK256FS_EN); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: format |= TWL4030_AIF_SLAVE_EN; format |= TWL4030_CLK256FS_EN; break; @@ -2038,9 +2043,8 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, old_format = twl4030_read(component, TWL4030_REG_VOICE_IF); format = old_format; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: format &= ~(TWL4030_VIF_SLAVE_EN); break; case SND_SOC_DAIFMT_CBS_CFS: @@ -2170,10 +2174,11 @@ static int twl4030_soc_probe(struct snd_soc_component *component) static void twl4030_soc_remove(struct snd_soc_component *component) { struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); - struct twl4030_codec_data *pdata = twl4030->pdata; + struct twl4030_board_params *board_params = twl4030->board_params; - if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) - gpio_free(pdata->hs_extmute_gpio); + if (board_params && board_params->hs_extmute && + gpio_is_valid(board_params->hs_extmute_gpio)) + gpio_free(board_params->hs_extmute_gpio); } static const struct snd_soc_component_driver soc_component_dev_twl4030 = { @@ -2190,7 +2195,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl4030 = { .num_dapm_routes = ARRAY_SIZE(intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int twl4030_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index b37203336c4e..dd5ee5dc0cd7 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1153,7 +1153,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl6040 = { .suspend_bias_off = 1, .idle_bias_on = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int twl6040_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c index 21ab8c5487ba..eace96533600 100644 --- a/sound/soc/codecs/uda1334.c +++ b/sound/soc/codecs/uda1334.c @@ -169,10 +169,10 @@ static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | - SND_SOC_DAIFMT_MASTER_MASK); + SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS)) { + SND_SOC_DAIFMT_CBC_CFC)) { dev_err(codec_dai->dev, "Invalid DAI format\n"); return -EINVAL; } @@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda1334 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id uda1334_of_match[] = { diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index bf9182cedb82..1a62bec94005 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -272,9 +272,9 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, pr_debug("%s fmt: %08X\n", __func__, fmt); - /* codec supports only full slave mode */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - printk(KERN_ERR "%s unsupported slave mode\n", __func__); + /* codec supports only full consumer mode */ + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) { + printk(KERN_ERR "%s unsupported clocking mode\n", __func__); return -EINVAL; } @@ -450,7 +450,7 @@ static int uda134x_soc_probe(struct snd_soc_component *component) struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); struct uda134x_platform_data *pd = uda134x->pd; const struct snd_soc_dapm_widget *widgets; - unsigned num_widgets; + unsigned int num_widgets; int ret; printk(KERN_INFO "UDA134X SoC Audio Codec\n"); @@ -527,7 +527,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda134x = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config uda134x_regmap_config = { diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 89f2bfeeb70e..fdaaee845176 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -435,8 +435,8 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai, iface |= R01_SFORI_MSB | R01_SFORO_MSB; } - /* DATAI is slave only, so in single-link mode, this has to be slave */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + /* DATAI is consumer only */ + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) return -EINVAL; uda1380_write_reg_cache(component, UDA1380_IFACE, iface); @@ -465,8 +465,8 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai, iface |= R01_SFORI_MSB; } - /* DATAI is slave only, so this has to be slave */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + /* DATAI is consumer only */ + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) return -EINVAL; uda1380_write(component, UDA1380_IFACE, iface); @@ -495,7 +495,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai, iface |= R01_SFORO_MSB; } - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFP) iface |= R01_SIM; uda1380_write(component, UDA1380_IFACE, iface); @@ -736,11 +736,9 @@ static const struct snd_soc_component_driver soc_component_dev_uda1380 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int uda1380_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int uda1380_i2c_probe(struct i2c_client *i2c) { struct uda1380_platform_data *pdata = i2c->dev.platform_data; struct uda1380_priv *uda1380; @@ -800,7 +798,7 @@ static struct i2c_driver uda1380_i2c_driver = { .name = "uda1380-codec", .of_match_table = uda1380_of_match, }, - .probe = uda1380_i2c_probe, + .probe_new = uda1380_i2c_probe, .id_table = uda1380_i2c_id, }; diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 405128ccb4b0..1911750f7445 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/pm_runtime.h> #include <linux/printk.h> #include <linux/delay.h> #include <linux/kernel.h> @@ -711,6 +712,16 @@ static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data) static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) { struct snd_soc_component *component = mbhc->component; + int ret; + + ret = pm_runtime_get_sync(component->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(component->dev, + "pm_runtime_get_sync failed in %s, ret %d\n", + __func__, ret); + pm_runtime_put_noidle(component->dev); + return ret; + } mutex_lock(&mbhc->lock); @@ -751,6 +762,9 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mutex_unlock(&mbhc->lock); + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + return 0; } @@ -1022,6 +1036,52 @@ static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) return plug_type; } +static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { + if (mbhc->cfg->micb_mv == micbias_mv) + hs_threshold = mbhc->cfg->hs_thr; + else + hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) / + WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc) +{ + bool is_spl_hs = false; + int output_mv, hs_threshold, hph_threshold; + + if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + return false; + + /* Bump up MIC_BIAS2 to 2.7V */ + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true); + usleep_range(10000, 10100); + + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc); + hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); + + if (!(output_mv > hs_threshold || output_mv < hph_threshold)) + is_spl_hs = true; + + /* Back MIC_BIAS2 to 1.8v if the type is not special headset */ + if (!is_spl_hs) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false); + /* Add 10ms delay for micbias to settle */ + usleep_range(10000, 10100); + } + + return is_spl_hs; +} + static void wcd_correct_swch_plug(struct work_struct *work) { struct wcd_mbhc *mbhc; @@ -1029,12 +1089,23 @@ static void wcd_correct_swch_plug(struct work_struct *work) enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; unsigned long timeout; int pt_gnd_mic_swap_cnt = 0; - int output_mv, cross_conn, hs_threshold, try = 0; + int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv; + bool is_spl_hs = false; bool is_pa_on; + int ret; mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); component = mbhc->component; + ret = pm_runtime_get_sync(component->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(component->dev, + "pm_runtime_get_sync failed in %s, ret %d\n", + __func__, ret); + pm_runtime_put_noidle(component->dev); + return; + } + micbias_mv = wcd_mbhc_get_micbias(mbhc); hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); /* Mask ADC COMPLETE interrupt */ @@ -1097,6 +1168,16 @@ correct_plug_type: plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); + if (output_mv > hs_threshold && !is_spl_hs) { + is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + if (is_spl_hs) { + hs_threshold *= wcd_mbhc_get_micbias(mbhc); + hs_threshold /= micbias_mv; + } + } + if ((output_mv <= hs_threshold) && !is_pa_on) { /* Check for cross connection*/ cross_conn = wcd_check_cross_conn(mbhc); @@ -1110,7 +1191,7 @@ correct_plug_type: pt_gnd_mic_swap_cnt = 0; plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); continue; - } else if (cross_conn < 0) /* Error */ + } else /* Error if (cross_conn < 0) */ continue; if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) { @@ -1122,14 +1203,19 @@ correct_plug_type: } } - if (output_mv > hs_threshold) /* cable is extension cable */ + /* cable is extension cable */ + if (output_mv > hs_threshold || mbhc->force_linein) plug_type = MBHC_PLUG_TYPE_HIGH_HPH; } wcd_mbhc_bcs_enable(mbhc, plug_type, true); - if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) - wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); + if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { + if (is_spl_hs) + plug_type = MBHC_PLUG_TYPE_HEADSET; + else + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); + } wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); @@ -1169,6 +1255,9 @@ exit: if (mbhc->mbhc_cb->hph_pull_down_ctrl) mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); } static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) @@ -1176,7 +1265,6 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) struct wcd_mbhc *mbhc = data; unsigned long timeout; int adc_threshold, output_mv, retry = 0; - bool hphpa_on = false; mutex_lock(&mbhc->lock); timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); @@ -1210,10 +1298,6 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) wcd_mbhc_elec_hs_report_unplug(mbhc); wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); - if (hphpa_on) { - hphpa_on = false; - wcd_mbhc_write_field(mbhc, WCD_MBHC_HPH_PA_EN, 3); - } exit: mutex_unlock(&mbhc->lock); return IRQ_HANDLED; @@ -1222,7 +1306,7 @@ exit: static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) { struct wcd_mbhc *mbhc = data; - u8 clamp_state = 0; + u8 clamp_state; u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; /* diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index bc5d68c53e5a..d2548fdf9ae5 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -24,6 +24,8 @@ #include "wcd9335.h" #include "wcd-clsh-v2.h" +#include <dt-bindings/sound/qcom,wcd9335.h> + #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) @@ -204,17 +206,6 @@ enum wcd9335_sido_voltage { }; enum { - AIF1_PB = 0, - AIF1_CAP, - AIF2_PB, - AIF2_CAP, - AIF3_PB, - AIF3_CAP, - AIF4_PB, - NUM_CODEC_DAIS, -}; - -enum { COMPANDER_1, /* HPH_L */ COMPANDER_2, /* HPH_R */ COMPANDER_3, /* LO1_DIFF */ @@ -341,8 +332,8 @@ struct wcd9335_codec { int reset_gpio; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; - unsigned int rx_port_value; - unsigned int tx_port_value; + unsigned int rx_port_value[WCD9335_RX_MAX]; + unsigned int tx_port_value[WCD9335_TX_MAX]; int hph_l_gain; int hph_r_gain; u32 rx_bias_count; @@ -1269,10 +1260,11 @@ static const struct snd_kcontrol_new sb_tx8_mux = static int slim_rx_mux_get(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); - struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev); + u32 port_id = w->shift; - ucontrol->value.enumerated.item[0] = wcd->rx_port_value; + ucontrol->value.enumerated.item[0] = wcd->rx_port_value[port_id]; return 0; } @@ -1286,11 +1278,17 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc, struct snd_soc_dapm_update *update = NULL; u32 port_id = w->shift; - wcd->rx_port_value = ucontrol->value.enumerated.item[0]; + if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0]) + return 0; + + wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0]; + + /* Remove channel from any list it's in before adding it to a new one */ + list_del_init(&wcd->rx_chs[port_id].list); - switch (wcd->rx_port_value) { + switch (wcd->rx_port_value[port_id]) { case 0: - list_del_init(&wcd->rx_chs[port_id].list); + /* Channel already removed from lists. Nothing to do here */ break; case 1: list_add_tail(&wcd->rx_chs[port_id].list, @@ -1309,11 +1307,11 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc, &wcd->dai[AIF4_PB].slim_ch_list); break; default: - dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value); + dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value[port_id]); goto err; } - snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value, + snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id], e, update); return 0; @@ -1327,8 +1325,13 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc, struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc); + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kc->private_value; + int dai_id = widget->shift; + int port_id = mixer->shift; - ucontrol->value.integer.value[0] = wcd->tx_port_value; + ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id] == dai_id; return 0; } @@ -1351,12 +1354,12 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc, case AIF2_CAP: case AIF3_CAP: /* only add to the list if value not set */ - if (enable && !(wcd->tx_port_value & BIT(port_id))) { - wcd->tx_port_value |= BIT(port_id); + if (enable && wcd->tx_port_value[port_id] != dai_id) { + wcd->tx_port_value[port_id] = dai_id; list_add_tail(&wcd->tx_chs[port_id].list, &wcd->dai[dai_id].slim_ch_list); - } else if (!enable && (wcd->tx_port_value & BIT(port_id))) { - wcd->tx_port_value &= ~BIT(port_id); + } else if (!enable && wcd->tx_port_value[port_id] == dai_id) { + wcd->tx_port_value[port_id] = -1; list_del_init(&wcd->tx_chs[port_id].list); } break; @@ -1806,11 +1809,11 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; shift = (tx_port << 1); shift_val = 0x03; - } else if ((tx_port >= 4) && (tx_port < 8)) { + } else if (tx_port < 8) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; shift = ((tx_port - 4) << 1); shift_val = 0x03; - } else if ((tx_port >= 8) && (tx_port < 11)) { + } else if (tx_port < 11) { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; shift = ((tx_port - 8) << 1); shift_val = 0x03; @@ -1818,12 +1821,10 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; shift = 0; shift_val = 0x0F; - } else if (tx_port == 13) { + } else /* (tx_port == 13) */ { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; shift = 4; shift_val = 0x03; - } else { - return -EINVAL; } tx_mux_sel = snd_soc_component_read(comp, tx_port_reg) & @@ -1971,8 +1972,8 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - slim_stream_unprepare(dai_data->sruntime); slim_stream_disable(dai_data->sruntime); + slim_stream_unprepare(dai_data->sruntime); break; default: break; @@ -2252,51 +2253,42 @@ static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, static const struct snd_kcontrol_new wcd9335_snd_controls[] = { /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", - WCD9335_CDC_RX0_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", - WCD9335_CDC_RX1_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", - WCD9335_CDC_RX2_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", - WCD9335_CDC_RX3_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", - WCD9335_CDC_RX4_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", - WCD9335_CDC_RX5_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", - WCD9335_CDC_RX6_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", - WCD9335_CDC_RX7_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", - WCD9335_CDC_RX8_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + -84, 40, digital_gain), SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), @@ -4923,6 +4915,7 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), .dapm_routes = wcd9335_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map), + .endianness = 1, }; static int wcd9335_probe(struct wcd9335_codec *wcd) @@ -5018,16 +5011,22 @@ static const struct regmap_irq wcd9335_codec_irqs[] = { }, }; +static const unsigned int wcd9335_config_regs[] = { + WCD9335_INTR_LEVEL0, +}; + static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { .name = "wcd9335_pin1_irq", .status_base = WCD9335_INTR_PIN1_STATUS0, .mask_base = WCD9335_INTR_PIN1_MASK0, .ack_base = WCD9335_INTR_PIN1_CLEAR0, - .type_base = WCD9335_INTR_LEVEL0, - .num_type_reg = 4, .num_regs = 4, .irqs = wcd9335_codec_irqs, .num_irqs = ARRAY_SIZE(wcd9335_codec_irqs), + .config_base = wcd9335_config_regs, + .num_config_bases = ARRAY_SIZE(wcd9335_config_regs), + .num_config_regs = 4, + .set_type_config = regmap_irq_set_type_config_simple, }; static int wcd9335_parse_dt(struct wcd9335_codec *wcd) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index e63c6b723d76..28175c746b9a 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1274,29 +1274,7 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src) if (sido_src == wcd->sido_input_src) return 0; - if (sido_src == SIDO_SOURCE_INTERNAL) { - regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL, - WCD934X_ANA_BUCK_HI_ACCU_EN_MASK, 0); - usleep_range(100, 110); - regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL, - WCD934X_ANA_BUCK_HI_ACCU_PRE_ENX_MASK, 0x0); - usleep_range(100, 110); - regmap_update_bits(wcd->regmap, WCD934X_ANA_RCO, - WCD934X_ANA_RCO_BG_EN_MASK, 0); - usleep_range(100, 110); - regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL, - WCD934X_ANA_BUCK_PRE_EN1_MASK, - WCD934X_ANA_BUCK_PRE_EN1_ENABLE); - usleep_range(100, 110); - regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL, - WCD934X_ANA_BUCK_PRE_EN2_MASK, - WCD934X_ANA_BUCK_PRE_EN2_ENABLE); - usleep_range(100, 110); - regmap_update_bits(wcd->regmap, WCD934X_ANA_BUCK_CTL, - WCD934X_ANA_BUCK_HI_ACCU_EN_MASK, - WCD934X_ANA_BUCK_HI_ACCU_ENABLE); - usleep_range(100, 110); - } else if (sido_src == SIDO_SOURCE_RCO_BG) { + if (sido_src == SIDO_SOURCE_RCO_BG) { regmap_update_bits(wcd->regmap, WCD934X_ANA_RCO, WCD934X_ANA_RCO_BG_EN_MASK, WCD934X_ANA_RCO_BG_ENABLE); @@ -1382,8 +1360,6 @@ static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd) regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG, WCD934X_EXT_CLK_BUF_EN_MASK | WCD934X_MCLK_EN_MASK, 0x0); - wcd934x_set_sido_input_src(wcd, SIDO_SOURCE_INTERNAL); - regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS, WCD934X_ANA_BIAS_EN_MASK, 0); regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS, @@ -1937,8 +1913,8 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - slim_stream_unprepare(dai_data->sruntime); slim_stream_disable(dai_data->sruntime); + slim_stream_unprepare(dai_data->sruntime); break; default: break; @@ -3023,14 +2999,14 @@ static int wcd934x_hph_impedance_get(struct snd_kcontrol *kcontrol, return 0; } static const struct snd_kcontrol_new hph_type_detect_controls[] = { - SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0, wcd934x_get_hph_type, NULL), }; static const struct snd_kcontrol_new impedance_detect_controls[] = { - SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0, wcd934x_hph_impedance_get, NULL), - SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0, wcd934x_hph_impedance_get, NULL), }; @@ -3308,13 +3284,16 @@ static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc, mode_val = ucontrol->value.enumerated.item[0]; + if (mode_val == wcd->hph_mode) + return 0; + if (mode_val == 0) { dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); mode_val = CLS_H_LOHIFI; } wcd->hph_mode = mode_val; - return 0; + return 1; } static int slim_rx_mux_get(struct snd_kcontrol *kc, @@ -3423,7 +3402,7 @@ static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc, { struct soc_enum *e = (struct soc_enum *)kc->private_value; struct snd_soc_component *component; - int reg, val, ret; + int reg, val; component = snd_soc_dapm_kcontrol_component(kc); val = ucontrol->value.enumerated.item[0]; @@ -3446,9 +3425,7 @@ static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc, WCD934X_RX_DLY_ZN_EN_MASK, WCD934X_RX_DLY_ZN_DISABLE); - ret = snd_soc_dapm_put_enum_double(kc, ucontrol); - - return ret; + return snd_soc_dapm_put_enum_double(kc, ucontrol); } static int wcd934x_dec_enum_put(struct snd_kcontrol *kcontrol, @@ -5870,6 +5847,7 @@ static const struct snd_soc_component_driver wcd934x_component_drv = { .dapm_routes = wcd934x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd934x_audio_map), .set_jack = wcd934x_codec_set_jack, + .endianness = 1, }; static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) @@ -5885,6 +5863,7 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) } wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np); + of_node_put(ifc_dev_np); if (!wcd->sidev) { dev_err(dev, "Unable to get SLIM Interface device\n"); return -EINVAL; diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index 1fa05ec7459a..1bf3c06a2b62 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -249,6 +249,7 @@ static int wcd9380_probe(struct sdw_slave *pdev, SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; pdev->prop.lane_control_support = true; + pdev->prop.simple_clk_stop_capable = true; if (wcd->is_tx) { pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); pdev->prop.src_dpn_prop = wcd938x_dpn_prop; diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 67151c7770c6..aca06a4026f3 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -6,6 +6,7 @@ #include <linux/platform_device.h> #include <linux/device.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/pm_runtime.h> #include <linux/component.h> @@ -194,6 +195,7 @@ struct wcd938x_priv { int ear_rx_path; int variant; int reset_gpio; + struct gpio_desc *us_euro_gpio; u32 micb1_mv; u32 micb2_mv; u32 micb3_mv; @@ -1296,7 +1298,6 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = { .num_regs = 3, .status_base = WCD938X_DIGITAL_INTR_STATUS_0, .mask_base = WCD938X_DIGITAL_INTR_MASK_0, - .type_base = WCD938X_DIGITAL_INTR_LEVEL_0, .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, .use_ack = 1, .runtime_pm = true, @@ -1432,14 +1433,10 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info, return 0; } -static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable) +static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable) { - u8 port_num; - - port_num = wcd->ch_info[ch_id].port_num; - return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id], - &wcd->port_config[port_num], + &wcd->port_config[port_num - 1], enable); } @@ -2508,7 +2505,7 @@ static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int path = e->shift_l; - ucontrol->value.integer.value[0] = wcd938x->tx_mode[path]; + ucontrol->value.enumerated.item[0] = wcd938x->tx_mode[path]; return 0; } @@ -2521,6 +2518,9 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int path = e->shift_l; + if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0]) + return 0; + wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0]; return 1; @@ -2532,7 +2532,7 @@ static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - ucontrol->value.integer.value[0] = wcd938x->hph_mode; + ucontrol->value.enumerated.item[0] = wcd938x->hph_mode; return 0; } @@ -2543,6 +2543,9 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0]) + return 0; + wcd938x->hph_mode = ucontrol->value.enumerated.item[0]; return 1; @@ -2563,7 +2566,7 @@ static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol, WCD938X_EAR_GAIN_MASK, ucontrol->value.integer.value[0]); - return 0; + return 1; } static int wcd938x_get_compander(struct snd_kcontrol *kcontrol, @@ -2593,6 +2596,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); struct wcd938x_sdw_priv *wcd; int value = ucontrol->value.integer.value[0]; + int portidx; struct soc_mixer_control *mc; bool hphr; @@ -2606,12 +2610,14 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, else wcd938x->comp1_enable = value; + portidx = wcd->ch_info[mc->reg].port_num; + if (value) - wcd938x_connect_port(wcd, mc->reg, true); + wcd938x_connect_port(wcd, portidx, mc->reg, true); else - wcd938x_connect_port(wcd, mc->reg, false); + wcd938x_connect_port(wcd, portidx, mc->reg, false); - return 0; + return 1; } static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol, @@ -2631,6 +2637,9 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->ldoh == ucontrol->value.integer.value[0]) + return 0; + wcd938x->ldoh = ucontrol->value.integer.value[0]; return 1; @@ -2653,6 +2662,9 @@ static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->bcs_dis == ucontrol->value.integer.value[0]) + return 0; + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; return 1; @@ -2882,9 +2894,11 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol, struct wcd938x_sdw_priv *wcd; struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; int dai_id = mixer->shift; - int portidx = mixer->reg; + int portidx, ch_idx = mixer->reg; + wcd = wcd938x->sdw_priv[dai_id]; + portidx = wcd->ch_info[ch_idx].port_num; ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; @@ -2899,12 +2913,14 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol, struct wcd938x_sdw_priv *wcd; struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; - int portidx = mixer->reg; + int ch_idx = mixer->reg; + int portidx; int dai_id = mixer->shift; bool enable; wcd = wcd938x->sdw_priv[dai_id]; + portidx = wcd->ch_info[ch_idx].port_num; if (ucontrol->value.integer.value[0]) enable = true; else @@ -2912,9 +2928,9 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol, wcd->port_enable[portidx] = enable; - wcd938x_connect_port(wcd, portidx, enable); + wcd938x_connect_port(wcd, portidx, ch_idx, enable); - return 0; + return 1; } @@ -3086,7 +3102,7 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon int micb_num, bool req_en) { struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - int rc, micb_mv; + int micb_mv; if (micb_num != MIC_BIAS_2) return -EINVAL; @@ -3100,9 +3116,7 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->micb2_mv; - rc = wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); - - return rc; + return wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); } static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, @@ -3574,14 +3588,14 @@ static int wcd938x_hph_impedance_get(struct snd_kcontrol *kcontrol, } static const struct snd_kcontrol_new hph_type_detect_controls[] = { - SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0, wcd938x_get_hph_type, NULL), }; static const struct snd_kcontrol_new impedance_detect_controls[] = { - SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0, wcd938x_hph_impedance_get, NULL), - SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0, wcd938x_hph_impedance_get, NULL), }; @@ -4165,6 +4179,7 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .dapm_routes = wcd938x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), .set_jack = wcd938x_codec_set_jack, + .endianness = 1, }; static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd) @@ -4198,6 +4213,22 @@ static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_pri dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); } +static bool wcd938x_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value; + + struct wcd938x_priv *wcd938x; + + wcd938x = snd_soc_component_get_drvdata(component); + + value = gpiod_get_value(wcd938x->us_euro_gpio); + + gpiod_set_value(wcd938x->us_euro_gpio, !value); + + return true; +} + + static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device *dev) { struct wcd_mbhc_config *cfg = &wcd938x->mbhc_cfg; @@ -4210,6 +4241,15 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device return wcd938x->reset_gpio; } + wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", + GPIOD_OUT_LOW); + if (IS_ERR(wcd938x->us_euro_gpio)) { + dev_err(dev, "us-euro swap Control GPIO not found\n"); + return PTR_ERR(wcd938x->us_euro_gpio); + } + + cfg->swap_gnd_mic = wcd938x_swap_gnd_mic; + wcd938x->supplies[0].supply = "vdd-rxtx"; wcd938x->supplies[1].supply = "vdd-io"; wcd938x->supplies[2].supply = "vdd-buck"; @@ -4287,7 +4327,7 @@ static int wcd938x_codec_set_sdw_stream(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { .hw_params = wcd938x_codec_hw_params, .hw_free = wcd938x_codec_free, - .set_sdw_stream = wcd938x_codec_set_sdw_stream, + .set_stream = wcd938x_codec_set_sdw_stream, }; static struct snd_soc_dai_driver wcd938x_dais[] = { @@ -4419,16 +4459,6 @@ static const struct component_master_ops wcd938x_comp_ops = { .unbind = wcd938x_unbind, }; -static int wcd938x_compare_of(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -static void wcd938x_release_of(struct device *dev, void *data) -{ - of_node_put(data); -} - static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, struct device *dev, struct component_match **matchptr) @@ -4444,8 +4474,8 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, } of_node_get(wcd938x->rxnode); - component_match_add_release(dev, matchptr, wcd938x_release_of, - wcd938x_compare_of, wcd938x->rxnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd938x->rxnode); wcd938x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); if (!wcd938x->txnode) { @@ -4453,8 +4483,8 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, return -ENODEV; } of_node_get(wcd938x->txnode); - component_match_add_release(dev, matchptr, wcd938x_release_of, - wcd938x_compare_of, wcd938x->txnode); + component_match_add_release(dev, matchptr, component_release_of, + component_compare_of, wcd938x->txnode); return 0; } diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index d8ced4559bf2..626278e4c923 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -414,13 +414,13 @@ int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt) case WL1273_MODE_FM_TX: *fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; break; case WL1273_MODE_BT: *fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; break; default: @@ -475,7 +475,6 @@ static const struct snd_soc_component_driver soc_component_dev_wl1273 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wl1273_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 28b4656c4e14..034a4e858c7e 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -789,7 +789,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm0010 = { .num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) @@ -969,7 +968,7 @@ static int wm0010_spi_probe(struct spi_device *spi) return 0; } -static int wm0010_spi_remove(struct spi_device *spi) +static void wm0010_spi_remove(struct spi_device *spi) { struct wm0010_priv *wm0010 = spi_get_drvdata(spi); @@ -980,8 +979,6 @@ static int wm0010_spi_remove(struct spi_device *spi) if (wm0010->irq) free_irq(wm0010->irq, wm0010); - - return 0; } static struct spi_driver wm0010_spi_driver = { diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index d6ffe99550fe..0064a607ec68 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -144,7 +144,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm1250_ev1 = { .set_bias_level = wm1250_ev1_set_bias_level, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm1250_ev1_pdata(struct i2c_client *i2c) @@ -192,8 +191,7 @@ static void wm1250_ev1_free(struct i2c_client *i2c) gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios)); } -static int wm1250_ev1_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm1250_ev1_probe(struct i2c_client *i2c) { int id, board, rev, ret; @@ -230,11 +228,9 @@ static int wm1250_ev1_probe(struct i2c_client *i2c, return 0; } -static int wm1250_ev1_remove(struct i2c_client *i2c) +static void wm1250_ev1_remove(struct i2c_client *i2c) { wm1250_ev1_free(i2c); - - return 0; } static const struct i2c_device_id wm1250_ev1_i2c_id[] = { @@ -247,7 +243,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = { .driver = { .name = "wm1250-ev1", }, - .probe = wm1250_ev1_probe, + .probe_new = wm1250_ev1_probe, .remove = wm1250_ev1_remove, .id_table = wm1250_ev1_i2c_id, }; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 72e165cc6443..14b4fd97488c 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -536,7 +536,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, { struct i2c_client *i2c = wm2000->i2c; int i, j; - int ret; + int ret = 0; if (wm2000->anc_mode == mode) return 0; @@ -566,13 +566,13 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, ret = anc_transitions[i].step[j](i2c, anc_transitions[i].analogue); if (ret != 0) - return ret; + break; } if (anc_transitions[i].dest == ANC_OFF) clk_disable_unprepare(wm2000->mclk); - return 0; + return ret; } static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) @@ -803,12 +803,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm2000 = { .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map), .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm2000_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) +static int wm2000_i2c_probe(struct i2c_client *i2c) { struct wm2000_priv *wm2000; struct wm2000_platform_data *pdata; @@ -941,7 +938,7 @@ static struct i2c_driver wm2000_i2c_driver = { .driver = { .name = "wm2000", }, - .probe = wm2000_i2c_probe, + .probe_new = wm2000_i2c_probe, .id_table = wm2000_i2c_id, }; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 8863b533f9c4..0a65afa44a59 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2104,7 +2104,6 @@ static const struct snd_soc_component_driver soc_component_wm2200 = { .dapm_routes = wm2200_dapm_routes, .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static irqreturn_t wm2200_irq(int irq, void *data) @@ -2176,8 +2175,7 @@ static const unsigned int wm2200_mic_ctrl_reg[] = { WM2200_IN3L_CONTROL, }; -static int wm2200_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm2200_i2c_probe(struct i2c_client *i2c) { struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm2200_priv *wm2200; @@ -2416,7 +2414,7 @@ err_enable: return ret; } -static int wm2200_i2c_remove(struct i2c_client *i2c) +static void wm2200_i2c_remove(struct i2c_client *i2c) { struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c); @@ -2429,8 +2427,6 @@ static int wm2200_i2c_remove(struct i2c_client *i2c) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), wm2200->core_supplies); - - return 0; } #ifdef CONFIG_PM @@ -2489,7 +2485,7 @@ static struct i2c_driver wm2200_i2c_driver = { .name = "wm2200", .pm = &wm2200_pm, }, - .probe = wm2200_i2c_probe, + .probe_new = wm2200_i2c_probe, .remove = wm2200_i2c_remove, .id_table = wm2200_i2c_id, }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 9cab01ee4ee9..3b09d4a1684f 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2389,7 +2389,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5100 = { .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm5100_regmap = { @@ -2411,8 +2410,7 @@ static const unsigned int wm5100_mic_ctrl_reg[] = { WM5100_IN4L_CONTROL, }; -static int wm5100_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm5100_i2c_probe(struct i2c_client *i2c) { struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm5100_priv *wm5100; @@ -2637,7 +2635,7 @@ err: return ret; } -static int wm5100_i2c_remove(struct i2c_client *i2c) +static void wm5100_i2c_remove(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); @@ -2653,8 +2651,6 @@ static int wm5100_i2c_remove(struct i2c_client *i2c) gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); gpio_free(wm5100->pdata.ldo_ena); } - - return 0; } #ifdef CONFIG_PM @@ -2713,7 +2709,7 @@ static struct i2c_driver wm5100_i2c_driver = { .name = "wm5100", .pm = &wm5100_pm, }, - .probe = wm5100_i2c_probe, + .probe_new = wm5100_i2c_probe, .remove = wm5100_i2c_remove, .id_table = wm5100_i2c_id, }; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index da2f8998df87..adaf886b0a9d 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -680,12 +680,17 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); + uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); + int ret = 0; mutex_lock(&arizona->dac_comp_lock); - arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); + if (arizona->dac_comp_coeff != dac_comp_coeff) { + arizona->dac_comp_coeff = dac_comp_coeff; + ret = 1; + } mutex_unlock(&arizona->dac_comp_lock); - return 0; + return ret; } static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, @@ -706,12 +711,20 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int ret = 0; + + if (ucontrol->value.integer.value[0] > mc->max) + return -EINVAL; mutex_lock(&arizona->dac_comp_lock); - arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; + if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) { + arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; + ret = 1; + } mutex_unlock(&arizona->dac_comp_lock); - return 0; + return ret; } static const char * const wm5102_osr_text[] = { @@ -2015,7 +2028,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm5102_probe(struct platform_device *pdev) @@ -2130,6 +2142,7 @@ err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); err_jack_codec_dev: + pm_runtime_disable(&pdev->dev); arizona_jack_codec_dev_remove(&wm5102->core); return ret; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 4973ba1ed779..e0b971620d0f 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift; unsigned int lold, rold; unsigned int lena, rena; + bool change = false; int ret; snd_soc_dapm_mutex_lock(dapm); @@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, goto err; } - ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE, - mask, lnew | rnew); + ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE, + mask, lnew | rnew, &change); if (ret) { dev_err(arizona->dev, "Failed to set DRE: %d\n", ret); goto err; @@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol, if (!rnew && rold) wm5110_clear_pga_volume(arizona, mc->rshift); + if (change) + ret = 1; + err: snd_soc_dapm_mutex_unlock(dapm); @@ -2381,7 +2385,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm5110_probe(struct platform_device *pdev) @@ -2497,6 +2500,7 @@ err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); err_jack_codec_dev: + pm_runtime_disable(&pdev->dev); arizona_jack_codec_dev_remove(&wm5110->core); return ret; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 15d42ce3b21d..66bd281095e1 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1537,18 +1537,38 @@ static int wm8350_component_probe(struct snd_soc_component *component) wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, + ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, wm8350_hpl_jack_handler, 0, "Left jack detect", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, + if (ret != 0) + goto err; + + ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, wm8350_hpr_jack_handler, 0, "Right jack detect", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, + if (ret != 0) + goto free_jck_det_l; + + ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, wm8350_mic_handler, 0, "Microphone short", priv); - wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, + if (ret != 0) + goto free_jck_det_r; + + ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, wm8350_mic_handler, 0, "Microphone detect", priv); + if (ret != 0) + goto free_micscd; return 0; + +free_micscd: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv); +free_jck_det_r: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); +free_jck_det_l: + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); +err: + return ret; } static void wm8350_component_remove(struct snd_soc_component *component) @@ -1593,7 +1613,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8350 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8350_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index bf5e77c86aed..19ce839f6ef7 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1322,7 +1322,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8400 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8400_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a18e2290b8c8..e13f9780a111 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -592,7 +592,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8510 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8510_of_match[] = { @@ -646,8 +645,7 @@ static struct spi_driver wm8510_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8510_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8510_i2c_probe(struct i2c_client *i2c) { struct wm8510_priv *wm8510; int ret; @@ -680,7 +678,7 @@ static struct i2c_driver wm8510_i2c_driver = { .name = "wm8510", .of_match_table = wm8510_of_match, }, - .probe = wm8510_i2c_probe, + .probe_new = wm8510_i2c_probe, .id_table = wm8510_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index c8b50aac6c18..66f6371d8acf 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -422,7 +422,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8523 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8523_of_match[] = { @@ -443,8 +442,7 @@ static const struct regmap_config wm8523_regmap = { .volatile_reg = wm8523_volatile_register, }; -static int wm8523_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8523_i2c_probe(struct i2c_client *i2c) { struct wm8523_priv *wm8523; unsigned int val; @@ -529,7 +527,7 @@ static struct i2c_driver wm8523_i2c_driver = { .name = "wm8523", .of_match_table = wm8523_of_match, }, - .probe = wm8523_i2c_probe, + .probe_new = wm8523_i2c_probe, .id_table = wm8523_i2c_id, }; diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index 81f858f6bd67..b56dcac60244 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -203,7 +203,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8524 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8524_of_match[] = { diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 85ad2f03cfd0..ca796aa0aeb7 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -966,7 +966,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8580 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8580_regmap = { @@ -996,8 +995,7 @@ static const struct of_device_id wm8580_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8580_of_match); -static int wm8580_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8580_i2c_probe(struct i2c_client *i2c) { const struct of_device_id *of_id; struct wm8580_priv *wm8580; @@ -1051,7 +1049,7 @@ static struct i2c_driver wm8580_i2c_driver = { .name = "wm8580", .of_match_table = wm8580_of_match, }, - .probe = wm8580_i2c_probe, + .probe_new = wm8580_i2c_probe, .id_table = wm8580_i2c_id, }; diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index bc4d161c59e5..383c6796e8a3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -378,7 +378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8711 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8711_of_match[] = { @@ -432,8 +431,7 @@ static struct spi_driver wm8711_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8711_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int wm8711_i2c_probe(struct i2c_client *client) { struct wm8711_priv *wm8711; int ret; @@ -466,7 +464,7 @@ static struct i2c_driver wm8711_i2c_driver = { .name = "wm8711", .of_match_table = wm8711_of_match, }, - .probe = wm8711_i2c_probe, + .probe_new = wm8711_i2c_probe, .id_table = wm8711_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index 1a118b75b539..d6b0a570dd87 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -55,7 +55,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8727 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8727_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 2cd58d133899..a3dbdbf40723 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -221,7 +221,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8728 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8728_of_match[] = { @@ -273,8 +272,7 @@ static struct spi_driver wm8728_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8728_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8728_i2c_probe(struct i2c_client *i2c) { struct wm8728_priv *wm8728; int ret; @@ -307,7 +305,7 @@ static struct i2c_driver wm8728_i2c_driver = { .name = "wm8728", .of_match_table = wm8728_of_match, }, - .probe = wm8728_i2c_probe, + .probe_new = wm8728_i2c_probe, .id_table = wm8728_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8731-i2c.c b/sound/soc/codecs/wm8731-i2c.c new file mode 100644 index 000000000000..fdf03bf91606 --- /dev/null +++ b/sound/soc/codecs/wm8731-i2c.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * wm8731-i2c.c -- WM8731 ALSA SoC Audio driver I2C code + * + * Copyright 2005 Openedhand Ltd. + * Copyright 2006-12 Wolfson Microelectronics, plc + * + * Author: Richard Purdie <richard@openedhand.com> + * + * Based on wm8753.c by Liam Girdwood + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> + +#include "wm8731.h" + + +static const struct of_device_id wm8731_of_match[] = { + { .compatible = "wlf,wm8731", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8731_of_match); + +static int wm8731_i2c_probe(struct i2c_client *i2c) +{ + struct wm8731_priv *wm8731; + int ret; + + wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv), + GFP_KERNEL); + if (wm8731 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, wm8731); + + wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); + if (IS_ERR(wm8731->regmap)) { + ret = PTR_ERR(wm8731->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return wm8731_init(&i2c->dev, wm8731); +} + +static const struct i2c_device_id wm8731_i2c_id[] = { + { "wm8731", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); + +static struct i2c_driver wm8731_i2c_driver = { + .driver = { + .name = "wm8731", + .of_match_table = wm8731_of_match, + }, + .probe_new = wm8731_i2c_probe, + .id_table = wm8731_i2c_id, +}; + +module_i2c_driver(wm8731_i2c_driver); + +MODULE_DESCRIPTION("ASoC WM8731 driver - I2C"); +MODULE_AUTHOR("Richard Purdie"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731-spi.c b/sound/soc/codecs/wm8731-spi.c new file mode 100644 index 000000000000..542ed097d89a --- /dev/null +++ b/sound/soc/codecs/wm8731-spi.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * wm8731.c -- WM8731 ALSA SoC Audio driver + * + * Copyright 2005 Openedhand Ltd. + * Copyright 2006-12 Wolfson Microelectronics, plc + * + * Author: Richard Purdie <richard@openedhand.com> + * + * Based on wm8753.c by Liam Girdwood + */ + +#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/of_device.h> + +#include "wm8731.h" + +static const struct of_device_id wm8731_of_match[] = { + { .compatible = "wlf,wm8731", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8731_of_match); + +static int wm8731_spi_probe(struct spi_device *spi) +{ + struct wm8731_priv *wm8731; + int ret; + + wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); + if (wm8731 == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, wm8731); + + wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); + if (IS_ERR(wm8731->regmap)) { + ret = PTR_ERR(wm8731->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return wm8731_init(&spi->dev, wm8731); +} + +static struct spi_driver wm8731_spi_driver = { + .driver = { + .name = "wm8731", + .of_match_table = wm8731_of_match, + }, + .probe = wm8731_spi_probe, +}; + +module_spi_driver(wm8731_spi_driver); + +MODULE_DESCRIPTION("ASoC WM8731 driver - SPI"); +MODULE_AUTHOR("Richard Purdie"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 86b1f6eaa599..d5ab3ba126a6 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -15,13 +15,9 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> -#include <linux/spi/spi.h> -#include <linux/of_device.h> -#include <linux/mutex.h> #include <linux/clk.h> #include <sound/core.h> #include <sound/pcm.h> @@ -32,7 +28,6 @@ #include "wm8731.h" -#define WM8731_NUM_SUPPLIES 4 static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { "AVDD", "HPVDD", @@ -40,21 +35,6 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { "DBVDD", }; -/* codec private data */ -struct wm8731_priv { - struct regmap *regmap; - struct clk *mclk; - struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; - const struct snd_pcm_hw_constraint_list *constraints; - unsigned int sysclk; - int sysclk_type; - int playback_fs; - bool deemph; - - struct mutex lock; -}; - - /* * wm8731 register cache */ @@ -429,12 +409,11 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; u16 iface = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -570,11 +549,38 @@ static struct snd_soc_dai_driver wm8731_dai = { .symmetric_rate = 1, }; -static int wm8731_request_supplies(struct device *dev, - struct wm8731_priv *wm8731) +static const struct snd_soc_component_driver soc_component_dev_wm8731 = { + .set_bias_level = wm8731_set_bias_level, + .controls = wm8731_snd_controls, + .num_controls = ARRAY_SIZE(wm8731_snd_controls), + .dapm_widgets = wm8731_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), + .dapm_routes = wm8731_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), + .suspend_bias_off = 1, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +int wm8731_init(struct device *dev, struct wm8731_priv *wm8731) { int ret = 0, i; + wm8731->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(wm8731->mclk)) { + ret = PTR_ERR(wm8731->mclk); + if (ret == -ENOENT) { + wm8731->mclk = NULL; + dev_warn(dev, "Assuming static MCLK\n"); + } else { + dev_err(dev, "Failed to get MCLK: %d\n", ret); + return ret; + } + } + + mutex_init(&wm8731->lock); + for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) wm8731->supplies[i].supply = wm8731_supply_names[i]; @@ -592,13 +598,6 @@ static int wm8731_request_supplies(struct device *dev, return ret; } - return 0; -} - -static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731) -{ - int ret = 0; - ret = wm8731_reset(wm8731->regmap); if (ret < 0) { dev_err(dev, "Failed to issue reset: %d\n", ret); @@ -619,36 +618,24 @@ static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731) regcache_mark_dirty(wm8731->regmap); + ret = devm_snd_soc_register_component(dev, + &soc_component_dev_wm8731, &wm8731_dai, 1); + if (ret != 0) { + dev_err(dev, "Failed to register CODEC: %d\n", ret); + goto err_regulator_enable; + } + + return 0; + err_regulator_enable: /* Regulators will be enabled by bias management */ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return ret; } +EXPORT_SYMBOL_GPL(wm8731_init); -static const struct snd_soc_component_driver soc_component_dev_wm8731 = { - .set_bias_level = wm8731_set_bias_level, - .controls = wm8731_snd_controls, - .num_controls = ARRAY_SIZE(wm8731_snd_controls), - .dapm_widgets = wm8731_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), - .dapm_routes = wm8731_intercon, - .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), - .suspend_bias_off = 1, - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, -}; - -static const struct of_device_id wm8731_of_match[] = { - { .compatible = "wlf,wm8731", }, - { } -}; - -MODULE_DEVICE_TABLE(of, wm8731_of_match); - -static const struct regmap_config wm8731_regmap = { +const struct regmap_config wm8731_regmap = { .reg_bits = 7, .val_bits = 9, @@ -659,177 +646,7 @@ static const struct regmap_config wm8731_regmap = { .reg_defaults = wm8731_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), }; - -#if defined(CONFIG_SPI_MASTER) -static int wm8731_spi_probe(struct spi_device *spi) -{ - struct wm8731_priv *wm8731; - int ret; - - wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); - if (wm8731 == NULL) - return -ENOMEM; - - wm8731->mclk = devm_clk_get(&spi->dev, "mclk"); - if (IS_ERR(wm8731->mclk)) { - ret = PTR_ERR(wm8731->mclk); - if (ret == -ENOENT) { - wm8731->mclk = NULL; - dev_warn(&spi->dev, "Assuming static MCLK\n"); - } else { - dev_err(&spi->dev, "Failed to get MCLK: %d\n", - ret); - return ret; - } - } - - mutex_init(&wm8731->lock); - - spi_set_drvdata(spi, wm8731); - - ret = wm8731_request_supplies(&spi->dev, wm8731); - if (ret != 0) - return ret; - - wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); - if (IS_ERR(wm8731->regmap)) { - ret = PTR_ERR(wm8731->regmap); - dev_err(&spi->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - - ret = wm8731_hw_init(&spi->dev, wm8731); - if (ret != 0) - return ret; - - ret = devm_snd_soc_register_component(&spi->dev, - &soc_component_dev_wm8731, &wm8731_dai, 1); - if (ret != 0) { - dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); - return ret; - } - - return 0; -} - -static struct spi_driver wm8731_spi_driver = { - .driver = { - .name = "wm8731", - .of_match_table = wm8731_of_match, - }, - .probe = wm8731_spi_probe, -}; -#endif /* CONFIG_SPI_MASTER */ - -#if IS_ENABLED(CONFIG_I2C) -static int wm8731_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8731_priv *wm8731; - int ret; - - wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv), - GFP_KERNEL); - if (wm8731 == NULL) - return -ENOMEM; - - wm8731->mclk = devm_clk_get(&i2c->dev, "mclk"); - if (IS_ERR(wm8731->mclk)) { - ret = PTR_ERR(wm8731->mclk); - if (ret == -ENOENT) { - wm8731->mclk = NULL; - dev_warn(&i2c->dev, "Assuming static MCLK\n"); - } else { - dev_err(&i2c->dev, "Failed to get MCLK: %d\n", - ret); - return ret; - } - } - - mutex_init(&wm8731->lock); - - i2c_set_clientdata(i2c, wm8731); - - ret = wm8731_request_supplies(&i2c->dev, wm8731); - if (ret != 0) - return ret; - - wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); - if (IS_ERR(wm8731->regmap)) { - ret = PTR_ERR(wm8731->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - - ret = wm8731_hw_init(&i2c->dev, wm8731); - if (ret != 0) - return ret; - - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_wm8731, &wm8731_dai, 1); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); - return ret; - } - - return 0; -} - -static int wm8731_i2c_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id wm8731_i2c_id[] = { - { "wm8731", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); - -static struct i2c_driver wm8731_i2c_driver = { - .driver = { - .name = "wm8731", - .of_match_table = wm8731_of_match, - }, - .probe = wm8731_i2c_probe, - .remove = wm8731_i2c_remove, - .id_table = wm8731_i2c_id, -}; -#endif - -static int __init wm8731_modinit(void) -{ - int ret = 0; -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8731_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8731_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8731_modinit); - -static void __exit wm8731_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8731_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8731_spi_driver); -#endif -} -module_exit(wm8731_exit); +EXPORT_SYMBOL_GPL(wm8731_regmap); MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 4fcf1226d7c2..8d5a7a9ca6b2 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h @@ -12,6 +12,13 @@ #ifndef _WM8731_H #define _WM8731_H +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +struct clk; +struct snd_pcm_hw_constraint_list; + /* WM8731 register space */ #define WM8731_LINVOL 0x00 @@ -33,4 +40,24 @@ #define WM8731_DAI 0 +#define WM8731_NUM_SUPPLIES 4 + +/* codec private data */ +struct wm8731_priv { + struct regmap *regmap; + struct clk *mclk; + struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; + const struct snd_pcm_hw_constraint_list *constraints; + unsigned int sysclk; + int sysclk_type; + int playback_fs; + bool deemph; + + struct mutex lock; +}; + +extern const struct regmap_config wm8731_regmap; + +int wm8731_init(struct device *dev, struct wm8731_priv *wm8731); + #endif diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 7a3f9fbe8d53..90b54343370c 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -583,7 +583,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8737 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8737_of_match[] = { @@ -606,8 +605,7 @@ static const struct regmap_config wm8737_regmap = { }; #if IS_ENABLED(CONFIG_I2C) -static int wm8737_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8737_i2c_probe(struct i2c_client *i2c) { struct wm8737_priv *wm8737; int ret, i; @@ -651,7 +649,7 @@ static struct i2c_driver wm8737_i2c_driver = { .name = "wm8737", .of_match_table = wm8737_of_match, }, - .probe = wm8737_i2c_probe, + .probe_new = wm8737_i2c_probe, .id_table = wm8737_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 0e3994326936..c7afa4f2795d 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -528,7 +528,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8741 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8741_of_match[] = { @@ -565,8 +564,7 @@ static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) } #if IS_ENABLED(CONFIG_I2C) -static int wm8741_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8741_i2c_probe(struct i2c_client *i2c) { struct wm8741_priv *wm8741; int ret, i; @@ -618,7 +616,7 @@ static struct i2c_driver wm8741_i2c_driver = { .name = "wm8741", .of_match_table = wm8741_of_match, }, - .probe = wm8741_i2c_probe, + .probe_new = wm8741_i2c_probe, .id_table = wm8741_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9491817020d8..2f6ee8d6639f 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -719,7 +719,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8750 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8750_of_match[] = { @@ -780,8 +779,7 @@ static struct spi_driver wm8750_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8750_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8750_i2c_probe(struct i2c_client *i2c) { struct wm8750_priv *wm8750; struct regmap *regmap; @@ -815,7 +813,7 @@ static struct i2c_driver wm8750_i2c_driver = { .name = "wm8750", .of_match_table = wm8750_of_match, }, - .probe = wm8750_i2c_probe, + .probe_new = wm8750_i2c_probe, .id_table = wm8750_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index deaa54be6268..bb18f58dc670 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1492,7 +1492,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8753 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8753_of_match[] = { @@ -1552,8 +1551,7 @@ static struct spi_driver wm8753_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8753_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8753_i2c_probe(struct i2c_client *i2c) { struct wm8753_priv *wm8753; int ret; @@ -1592,7 +1590,7 @@ static struct i2c_driver wm8753_i2c_driver = { .name = "wm8753", .of_match_table = wm8753_of_match, }, - .probe = wm8753_i2c_probe, + .probe_new = wm8753_i2c_probe, .id_table = wm8753_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 5f394065030d..e03fee8869c3 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -617,7 +617,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8770 = { .num_dapm_routes = ARRAY_SIZE(wm8770_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8770_of_match[] = { diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 554acf56130c..936ea24621b0 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -436,7 +436,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8776 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct of_device_id wm8776_of_match[] = { @@ -490,8 +489,7 @@ static struct spi_driver wm8776_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8776_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8776_i2c_probe(struct i2c_client *i2c) { struct wm8776_priv *wm8776; int ret; @@ -525,7 +523,7 @@ static struct i2c_driver wm8776_i2c_driver = { .name = "wm8776", .of_match_table = wm8776_of_match, }, - .probe = wm8776_i2c_probe, + .probe_new = wm8776_i2c_probe, .id_table = wm8776_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index f89855c616eb..95ff4339d103 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -99,7 +99,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8782_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index f97a75e64166..3ce1a39d76eb 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -14,8 +14,7 @@ #include "wm8804.h" -static int wm8804_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8804_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; @@ -26,10 +25,9 @@ static int wm8804_i2c_probe(struct i2c_client *i2c, return wm8804_probe(&i2c->dev, regmap); } -static int wm8804_i2c_remove(struct i2c_client *i2c) +static void wm8804_i2c_remove(struct i2c_client *i2c) { wm8804_remove(&i2c->dev); - return 0; } static const struct i2c_device_id wm8804_i2c_id[] = { @@ -62,7 +60,7 @@ static struct i2c_driver wm8804_i2c_driver = { .of_match_table = of_match_ptr(wm8804_of_match), .acpi_match_table = ACPI_PTR(wm8804_acpi_match), }, - .probe = wm8804_i2c_probe, + .probe_new = wm8804_i2c_probe, .remove = wm8804_i2c_remove, .id_table = wm8804_i2c_id }; diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c index 9a8da1511c34..628568724c20 100644 --- a/sound/soc/codecs/wm8804-spi.c +++ b/sound/soc/codecs/wm8804-spi.c @@ -24,10 +24,9 @@ static int wm8804_spi_probe(struct spi_device *spi) return wm8804_probe(&spi->dev, regmap); } -static int wm8804_spi_remove(struct spi_device *spi) +static void wm8804_spi_remove(struct spi_device *spi) { wm8804_remove(&spi->dev); - return 0; } static const struct of_device_id wm8804_of_match[] = { diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 21bf0cfa1e7e..0b234bae480e 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -546,7 +546,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8804 = { .num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; const struct regmap_config wm8804_regmap_config = { diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index bf3a4415a85f..03bbd85ebdf4 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1214,7 +1214,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8900 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8900_regmap = { @@ -1261,8 +1260,7 @@ static struct spi_driver wm8900_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8900_i2c_probe(struct i2c_client *i2c) { struct wm8900_priv *wm8900; int ret; @@ -1284,10 +1282,8 @@ static int wm8900_i2c_probe(struct i2c_client *i2c, return ret; } -static int wm8900_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void wm8900_i2c_remove(struct i2c_client *client) +{} static const struct i2c_device_id wm8900_i2c_id[] = { { "wm8900", 0 }, @@ -1299,7 +1295,7 @@ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "wm8900", }, - .probe = wm8900_i2c_probe, + .probe_new = wm8900_i2c_probe, .remove = wm8900_i2c_remove, .id_table = wm8900_i2c_id, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 75f30154c809..41346e5ec5ad 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1893,7 +1893,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8903 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8903_regmap = { @@ -1981,8 +1980,7 @@ static int wm8903_set_pdata_from_of(struct i2c_client *i2c, return 0; } -static int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8903_i2c_probe(struct i2c_client *i2c) { struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); struct wm8903_priv *wm8903; @@ -2132,7 +2130,7 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, if (ret != 0) { dev_err(wm8903->dev, "Failed to request IRQ: %d\n", ret); - return ret; + goto err; } /* Enable write sequencer interrupts */ @@ -2184,7 +2182,7 @@ err: return ret; } -static int wm8903_i2c_remove(struct i2c_client *client) +static void wm8903_i2c_remove(struct i2c_client *client) { struct wm8903_priv *wm8903 = i2c_get_clientdata(client); @@ -2193,8 +2191,6 @@ static int wm8903_i2c_remove(struct i2c_client *client) if (client->irq) free_irq(client->irq, wm8903); wm8903_free_gpio(wm8903); - - return 0; } static const struct of_device_id wm8903_of_match[] = { @@ -2214,7 +2210,7 @@ static struct i2c_driver wm8903_i2c_driver = { .name = "wm8903", .of_match_table = wm8903_of_match, }, - .probe = wm8903_i2c_probe, + .probe_new = wm8903_i2c_probe, .remove = wm8903_i2c_remove, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index a02a77fef360..ca6a01a230af 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2131,7 +2131,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8904 = { .set_bias_level = wm8904_set_bias_level, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8904_regmap = { @@ -2162,8 +2161,9 @@ static const struct of_device_id wm8904_of_match[] = { MODULE_DEVICE_TABLE(of, wm8904_of_match); #endif -static int wm8904_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id wm8904_i2c_id[]; + +static int wm8904_i2c_probe(struct i2c_client *i2c) { struct wm8904_priv *wm8904; unsigned int val; @@ -2197,6 +2197,8 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, return -EINVAL; wm8904->devtype = (enum wm8904_type)match->data; } else { + const struct i2c_device_id *id = + i2c_match_id(wm8904_i2c_id, i2c); wm8904->devtype = id->driver_data; } @@ -2328,7 +2330,7 @@ static struct i2c_driver wm8904_i2c_driver = { .name = "wm8904", .of_match_table = of_match_ptr(wm8904_of_match), }, - .probe = wm8904_i2c_probe, + .probe_new = wm8904_i2c_probe, .id_table = wm8904_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 440d048ef0c0..8dac9fd88547 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -734,7 +734,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8940 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8940_regmap = { @@ -750,8 +749,7 @@ static const struct regmap_config wm8940_regmap = { .volatile_reg = wm8940_volatile_register, }; -static int wm8940_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8940_i2c_probe(struct i2c_client *i2c) { struct wm8940_priv *wm8940; int ret; @@ -779,11 +777,18 @@ static const struct i2c_device_id wm8940_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); +static const struct of_device_id wm8940_of_match[] = { + { .compatible = "wlf,wm8940", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8940_of_match); + static struct i2c_driver wm8940_i2c_driver = { .driver = { .name = "wm8940", + .of_match_table = wm8940_of_match, }, - .probe = wm8940_i2c_probe, + .probe_new = wm8940_i2c_probe, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 513df47bd87d..05ef45672ebc 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -952,7 +952,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8955 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8955_regmap = { @@ -968,8 +967,7 @@ static const struct regmap_config wm8955_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; -static int wm8955_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8955_i2c_probe(struct i2c_client *i2c) { struct wm8955_priv *wm8955; int ret; @@ -1005,7 +1003,7 @@ static struct i2c_driver wm8955_i2c_driver = { .driver = { .name = "wm8955", }, - .probe = wm8955_i2c_probe, + .probe_new = wm8955_i2c_probe, .id_table = wm8955_i2c_id, }; diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index e4018ba3b19a..7878c7a58ff1 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -530,7 +530,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, wm8958_dsp_apply(component, mbc, wm8994->mbc_ena[mbc]); - return 0; + return 1; } #define WM8958_MBC_SWITCH(xname, xval) {\ @@ -656,7 +656,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol, wm8958_dsp_apply(component, vss, wm8994->vss_ena[vss]); - return 0; + return 1; } @@ -730,7 +730,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, wm8958_dsp_apply(component, hpf % 3, ucontrol->value.integer.value[0]); - return 0; + return 1; } #define WM8958_HPF_SWITCH(xname, xval) {\ @@ -824,7 +824,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol, wm8958_dsp_apply(component, eq, ucontrol->value.integer.value[0]); - return 0; + return 1; } #define WM8958_ENH_EQ_SWITCH(xname, xval) {\ diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 499604f1e178..0d167238a369 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -14,6 +14,7 @@ #include <linux/pm.h> #include <linux/clk.h> #include <linux/i2c.h> +#include <linux/acpi.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -45,6 +46,8 @@ #define WM8960_DISOP 0x40 #define WM8960_DRES_MASK 0x30 +#define WM8960_DSCH_TOUT 600 /* discharge timeout, ms */ + static bool is_pll_freq_available(unsigned int source, unsigned int target); static int wm8960_set_pll(struct snd_soc_component *component, unsigned int freq_in, unsigned int freq_out); @@ -133,6 +136,7 @@ struct wm8960_priv { int freq_in; bool is_stream_in_use[2]; struct wm8960_data pdata; + ktime_t dsch_start; }; #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) @@ -898,6 +902,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); int ret; + ktime_t tout; switch (level) { case SND_SOC_BIAS_ON: @@ -944,6 +949,11 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, case SND_SOC_BIAS_STANDBY: if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { + /* ensure discharge is complete */ + tout = WM8960_DSCH_TOUT - ktime_ms_delta(ktime_get(), wm8960->dsch_start); + if (tout > 0) + msleep(tout); + regcache_sync(wm8960->regmap); /* Enable anti-pop features */ @@ -973,9 +983,9 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); - /* Disable VMID and VREF, let them discharge */ + /* Disable VMID and VREF, mark discharge */ snd_soc_component_write(component, WM8960_POWER1, 0); - msleep(600); + wm8960->dsch_start = ktime_get(); break; } @@ -1368,7 +1378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8960 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8960_regmap = { @@ -1401,8 +1410,7 @@ static void wm8960_set_pdata_from_of(struct i2c_client *i2c, ARRAY_SIZE(pdata->hp_cfg)); } -static int wm8960_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8960_i2c_probe(struct i2c_client *i2c) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; @@ -1478,10 +1486,8 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, return ret; } -static int wm8960_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void wm8960_i2c_remove(struct i2c_client *client) +{} static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, @@ -1489,18 +1495,30 @@ static const struct i2c_device_id wm8960_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); +#if defined(CONFIG_OF) static const struct of_device_id wm8960_of_match[] = { { .compatible = "wlf,wm8960", }, { } }; MODULE_DEVICE_TABLE(of, wm8960_of_match); +#endif + +#if defined(CONFIG_ACPI) +static const struct acpi_device_id wm8960_acpi_match[] = { + { "1AEC8960", 0 }, /* Wolfson PCI ID + part ID */ + { "10138960", 0 }, /* Cirrus Logic PCI ID + part ID */ + { }, +}; +MODULE_DEVICE_TABLE(acpi, wm8960_acpi_match); +#endif static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", - .of_match_table = wm8960_of_match, + .of_match_table = of_match_ptr(wm8960_of_match), + .acpi_match_table = ACPI_PTR(wm8960_acpi_match), }, - .probe = wm8960_i2c_probe, + .probe_new = wm8960_i2c_probe, .remove = wm8960_i2c_remove, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index ef80d9fc1eec..7dc6aaf65576 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -895,7 +895,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8961 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8961_regmap = { @@ -911,8 +910,7 @@ static const struct regmap_config wm8961_regmap = { .readable_reg = wm8961_readable, }; -static int wm8961_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8961_i2c_probe(struct i2c_client *i2c) { struct wm8961_priv *wm8961; unsigned int val; @@ -977,7 +975,7 @@ static struct i2c_driver wm8961_i2c_driver = { .driver = { .name = "wm8961", }, - .probe = wm8961_i2c_probe, + .probe_new = wm8961_i2c_probe, .id_table = wm8961_i2c_id, }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index a5584ba962dc..b4b4355c6728 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1840,6 +1840,49 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5, 4, 1, 0, inmix_tlv), }; +static int tp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret, reg, val, mask; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + dev_err(component->dev, "Failed to resume device: %d\n", ret); + return ret; + } + + reg = WM8962_ADDITIONAL_CONTROL_4; + + if (!strcmp(w->name, "TEMP_HP")) { + mask = WM8962_TEMP_ENA_HP_MASK; + val = WM8962_TEMP_ENA_HP; + } else if (!strcmp(w->name, "TEMP_SPK")) { + mask = WM8962_TEMP_ENA_SPK_MASK; + val = WM8962_TEMP_ENA_SPK; + } else { + pm_runtime_put(component->dev); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + val = 0; + fallthrough; + case SND_SOC_DAPM_POST_PMU: + ret = snd_soc_component_update_bits(component, reg, mask, val); + break; + default: + WARN(1, "Invalid event %d\n", event); + pm_runtime_put(component->dev); + return -EINVAL; + } + + pm_runtime_put(component->dev); + + return 0; +} + static int cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -2049,6 +2092,13 @@ static SOC_ENUM_SINGLE_DECL(hpoutl_enum, static const struct snd_kcontrol_new hpoutl_mux = SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum); +static const char * const input_mode_text[] = { "Analog", "Digital" }; + +static SOC_ENUM_SINGLE_VIRT_DECL(input_mode_enum, input_mode_text); + +static const struct snd_kcontrol_new input_mode_mux = + SOC_DAPM_ENUM("Input Mode", input_mode_enum); + static const struct snd_kcontrol_new inpgal[] = { SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0), SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0), @@ -2133,8 +2183,10 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT, WM8962_DSP2_ENA_SHIFT, 0, dsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("TEMP_HP", SND_SOC_NOPM, 0, 0, tp_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("TEMP_SPK", SND_SOC_NOPM, 0, 0, tp_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0, inpgal, ARRAY_SIZE(inpgal)), @@ -2147,6 +2199,9 @@ SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0, SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0), +SND_SOC_DAPM_MUX("Input Mode L", SND_SOC_NOPM, 0, 0, &input_mode_mux), +SND_SOC_DAPM_MUX("Input Mode R", SND_SOC_NOPM, 0, 0, &input_mode_mux), + SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0), SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0), @@ -2226,16 +2281,19 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = { { "DMIC_ENA", NULL, "DMICDAT" }, + { "Input Mode L", "Analog", "MIXINL" }, + { "Input Mode L", "Digital", "DMIC_ENA" }, + { "Input Mode R", "Analog", "MIXINR" }, + { "Input Mode R", "Digital", "DMIC_ENA" }, + { "ADCL", NULL, "SYSCLK" }, { "ADCL", NULL, "TOCLK" }, - { "ADCL", NULL, "MIXINL" }, - { "ADCL", NULL, "DMIC_ENA" }, + { "ADCL", NULL, "Input Mode L" }, { "ADCL", NULL, "DSP2" }, { "ADCR", NULL, "SYSCLK" }, { "ADCR", NULL, "TOCLK" }, - { "ADCR", NULL, "MIXINR" }, - { "ADCR", NULL, "DMIC_ENA" }, + { "ADCR", NULL, "Input Mode R" }, { "ADCR", NULL, "DSP2" }, { "STL", "Left", "ADCL" }, @@ -2883,9 +2941,8 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s reinit_completion(&wm8962->fll_lock); - ret = pm_runtime_get_sync(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { - pm_runtime_put_noidle(component->dev); dev_err(component->dev, "Failed to resume device: %d\n", ret); return ret; } @@ -3017,9 +3074,8 @@ static irqreturn_t wm8962_irq(int irq, void *data) unsigned int active; int reg, ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { - pm_runtime_put_noidle(dev); dev_err(dev, "Failed to resume: %d\n", ret); return IRQ_NONE; } @@ -3491,7 +3547,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8962 = { .set_pll = wm8962_set_fll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; /* Improve power consumption for IN4 DC measurement mode */ @@ -3542,8 +3597,7 @@ static int wm8962_set_pdata_from_of(struct i2c_client *i2c, return PTR_ERR_OR_ZERO(pdata->mclk); } -static int wm8962_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8962_i2c_probe(struct i2c_client *i2c) { struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; @@ -3754,6 +3808,11 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, if (ret < 0) goto err_pm_runtime; + regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, + WM8962_TEMP_ENA_HP_MASK, 0); + regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, + WM8962_TEMP_ENA_SPK_MASK, 0); + regcache_cache_only(wm8962->regmap, true); /* The drivers should power up as needed */ @@ -3769,10 +3828,9 @@ err: return ret; } -static int wm8962_i2c_remove(struct i2c_client *client) +static void wm8962_i2c_remove(struct i2c_client *client) { pm_runtime_disable(&client->dev); - return 0; } #ifdef CONFIG_PM @@ -3858,6 +3916,7 @@ static int wm8962_runtime_suspend(struct device *dev) #endif static const struct dev_pm_ops wm8962_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; @@ -3879,7 +3938,7 @@ static struct i2c_driver wm8962_i2c_driver = { .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, - .probe = wm8962_i2c_probe, + .probe_new = wm8962_i2c_probe, .remove = wm8962_i2c_remove, .id_table = wm8962_i2c_id, }; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 21ae55c32a6d..4db9248de54b 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -659,7 +659,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8971 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8971_regmap = { @@ -672,11 +671,9 @@ static const struct regmap_config wm8971_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm8971_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8971_i2c_probe(struct i2c_client *i2c) { struct wm8971_priv *wm8971; - int ret; wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), GFP_KERNEL); @@ -689,10 +686,8 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8971); - ret = devm_snd_soc_register_component(&i2c->dev, + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm8971, &wm8971_dai, 1); - - return ret; } static const struct i2c_device_id wm8971_i2c_id[] = { @@ -705,7 +700,7 @@ static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", }, - .probe = wm8971_i2c_probe, + .probe_new = wm8971_i2c_probe, .id_table = wm8971_i2c_id, }; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index fdc68ab49742..010a394c705c 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -682,11 +682,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8974 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8974_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8974_i2c_probe(struct i2c_client *i2c) { struct wm8974_priv *priv; struct regmap *regmap; @@ -725,7 +723,7 @@ static struct i2c_driver wm8974_i2c_driver = { .name = "wm8974", .of_match_table = wm8974_of_match, }, - .probe = wm8974_i2c_probe, + .probe_new = wm8974_i2c_probe, .id_table = wm8974_i2c_id, }; diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 7091e1a9d516..a682f8020eb6 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1005,7 +1005,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8978 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8978_regmap_config = { @@ -1020,8 +1019,7 @@ static const struct regmap_config wm8978_regmap_config = { .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; -static int wm8978_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8978_i2c_probe(struct i2c_client *i2c) { struct wm8978_priv *wm8978; int ret; @@ -1074,7 +1072,7 @@ static struct i2c_driver wm8978_i2c_driver = { .name = "wm8978", .of_match_table = wm8978_of_match, }, - .probe = wm8978_i2c_probe, + .probe_new = wm8978_i2c_probe, .id_table = wm8978_i2c_id, }; diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index d8ed22a9caac..50e6ac6ccbe0 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -987,7 +987,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8983 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8983_regmap = { @@ -1035,8 +1034,7 @@ static struct spi_driver wm8983_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8983_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8983_i2c_probe(struct i2c_client *i2c) { struct wm8983_priv *wm8983; int ret; @@ -1070,7 +1068,7 @@ static struct i2c_driver wm8983_i2c_driver = { .driver = { .name = "wm8983", }, - .probe = wm8983_i2c_probe, + .probe_new = wm8983_i2c_probe, .id_table = wm8983_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index a7e01106fbc0..751aa6730833 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1116,7 +1116,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8985 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8985_regmap = { @@ -1167,10 +1166,12 @@ static struct spi_driver wm8985_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8985_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct i2c_device_id wm8985_i2c_id[]; + +static int wm8985_i2c_probe(struct i2c_client *i2c) { struct wm8985_priv *wm8985; + const struct i2c_device_id *id = i2c_match_id(wm8985_i2c_id, i2c); int ret; wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL); @@ -1205,7 +1206,7 @@ static struct i2c_driver wm8985_i2c_driver = { .driver = { .name = "wm8985", }, - .probe = wm8985_i2c_probe, + .probe_new = wm8985_i2c_probe, .id_table = wm8985_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 1d2f881bbcae..5dbdf647cd97 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -823,7 +823,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8988 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8988_regmap = { @@ -872,8 +871,7 @@ static struct spi_driver wm8988_spi_driver = { #endif /* CONFIG_SPI_MASTER */ #if IS_ENABLED(CONFIG_I2C) -static int wm8988_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8988_i2c_probe(struct i2c_client *i2c) { struct wm8988_priv *wm8988; int ret; @@ -907,7 +905,7 @@ static struct i2c_driver wm8988_i2c_driver = { .driver = { .name = "wm8988", }, - .probe = wm8988_i2c_probe, + .probe_new = wm8988_i2c_probe, .id_table = wm8988_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 938940777e5d..589af286f133 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1217,11 +1217,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8990 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8990_i2c_probe(struct i2c_client *i2c) { struct wm8990_priv *wm8990; int ret; @@ -1249,7 +1247,7 @@ static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", }, - .probe = wm8990_i2c_probe, + .probe_new = wm8990_i2c_probe, .id_table = wm8990_i2c_id, }; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 16bc8609d0d2..30121993b7b4 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1243,7 +1243,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8991 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8991_regmap = { @@ -1257,8 +1256,7 @@ static const struct regmap_config wm8991_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm8991_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8991_i2c_probe(struct i2c_client *i2c) { struct wm8991_priv *wm8991; unsigned int val; @@ -1325,7 +1323,7 @@ static struct i2c_driver wm8991_i2c_driver = { .driver = { .name = "wm8991", }, - .probe = wm8991_i2c_probe, + .probe_new = wm8991_i2c_probe, .id_table = wm8991_i2c_id, }; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index c4f41692b806..22a47acbc6d1 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1621,11 +1621,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8993 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; -static int wm8993_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8993_i2c_probe(struct i2c_client *i2c) { struct wm8993_priv *wm8993; unsigned int reg; @@ -1724,15 +1722,13 @@ err_enable: return ret; } -static int wm8993_i2c_remove(struct i2c_client *i2c) +static void wm8993_i2c_remove(struct i2c_client *i2c) { struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c); if (i2c->irq) free_irq(i2c->irq, wm8993); regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); - - return 0; } static const struct i2c_device_id wm8993_i2c_id[] = { @@ -1745,7 +1741,7 @@ static struct i2c_driver wm8993_i2c_driver = { .driver = { .name = "wm8993", }, - .probe = wm8993_i2c_probe, + .probe_new = wm8993_i2c_probe, .remove = wm8993_i2c_remove, .id_table = wm8993_i2c_id, }; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index f117ec0c489f..d3cfd3788f2a 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4614,7 +4614,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8994 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8994_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index b896d9c5bea0..eed48bf339f2 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2182,7 +2182,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8995 = { .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm8995_regmap = { @@ -2231,8 +2230,7 @@ static struct spi_driver wm8995_spi_driver = { #endif #if IS_ENABLED(CONFIG_I2C) -static int wm8995_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8995_i2c_probe(struct i2c_client *i2c) { struct wm8995_priv *wm8995; int ret; @@ -2270,7 +2268,7 @@ static struct i2c_driver wm8995_i2c_driver = { .driver = { .name = "wm8995", }, - .probe = wm8995_i2c_probe, + .probe_new = wm8995_i2c_probe, .id_table = wm8995_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 197ae7d84a49..b52ed89d631a 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2695,8 +2695,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8996 = { .set_pll = wm8996_set_fll, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, - }; #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ @@ -2755,8 +2753,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { }, }; -static int wm8996_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8996_i2c_probe(struct i2c_client *i2c) { struct wm8996_priv *wm8996; int ret, i; @@ -3068,7 +3065,7 @@ err: return ret; } -static int wm8996_i2c_remove(struct i2c_client *client) +static void wm8996_i2c_remove(struct i2c_client *client) { struct wm8996_priv *wm8996 = i2c_get_clientdata(client); @@ -3077,8 +3074,6 @@ static int wm8996_i2c_remove(struct i2c_client *client) gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_free(wm8996->pdata.ldo_ena); } - - return 0; } static const struct i2c_device_id wm8996_i2c_id[] = { @@ -3091,7 +3086,7 @@ static struct i2c_driver wm8996_i2c_driver = { .driver = { .name = "wm8996", }, - .probe = wm8996_i2c_probe, + .probe_new = wm8996_i2c_probe, .remove = wm8996_i2c_remove, .id_table = wm8996_i2c_id, }; diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 38ef631d1a1f..c0207e9a7d53 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1105,7 +1105,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = { .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8997_probe(struct platform_device *pdev) @@ -1188,6 +1187,7 @@ static int wm8997_probe(struct platform_device *pdev) err_spk_irqs: arizona_free_spk_irqs(arizona); err_jack_codec_dev: + pm_runtime_disable(&pdev->dev); arizona_jack_codec_dev_remove(&wm8997->core); return ret; diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 00b59fc9b1fe..79fc6bbaa3aa 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -108,6 +108,7 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int mode_reg, mode_index; unsigned int mux, inmode, src_val, mode_val; + int change, ret; mux = ucontrol->value.enumerated.item[0]; if (mux > 1) @@ -137,14 +138,20 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol, snd_soc_component_update_bits(component, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val); - snd_soc_component_update_bits(component, e->reg, - ARIZONA_IN1L_SRC_MASK | - ARIZONA_IN1L_SRC_SE_MASK, - src_val); + change = snd_soc_component_update_bits(component, e->reg, + ARIZONA_IN1L_SRC_MASK | + ARIZONA_IN1L_SRC_SE_MASK, + src_val); - return snd_soc_dapm_mux_update_power(dapm, kcontrol, - ucontrol->value.enumerated.item[0], - e, NULL); + ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, + ucontrol->value.enumerated.item[0], + e, NULL); + if (ret < 0) { + dev_err(arizona->dev, "Failed to update demux power state: %d\n", ret); + return ret; + } + + return change; } static const char * const wm8998_inmux_texts[] = { @@ -1325,7 +1332,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = { .num_dapm_routes = ARRAY_SIZE(wm8998_dapm_routes), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm8998_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 4a667ee82fe2..513ec0ba81bb 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1284,7 +1284,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9081 = { .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths), .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm9081_regmap = { @@ -1299,8 +1298,7 @@ static const struct regmap_config wm9081_regmap = { .cache_type = REGCACHE_RBTREE, }; -static int wm9081_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm9081_i2c_probe(struct i2c_client *i2c) { struct wm9081_priv *wm9081; unsigned int reg; @@ -1358,10 +1356,8 @@ static int wm9081_i2c_probe(struct i2c_client *i2c, return 0; } -static int wm9081_i2c_remove(struct i2c_client *client) -{ - return 0; -} +static void wm9081_i2c_remove(struct i2c_client *client) +{} static const struct i2c_device_id wm9081_i2c_id[] = { { "wm9081", 0 }, @@ -1373,7 +1369,7 @@ static struct i2c_driver wm9081_i2c_driver = { .driver = { .name = "wm9081", }, - .probe = wm9081_i2c_probe, + .probe_new = wm9081_i2c_probe, .remove = wm9081_i2c_remove, .id_table = wm9081_i2c_id, }; diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index e0231a54609c..ef3524c3f07f 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -543,8 +543,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9090 = { .suspend_bias_off = 1, .idle_bias_on = 1, .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, }; static const struct regmap_config wm9090_regmap = { @@ -561,8 +559,7 @@ static const struct regmap_config wm9090_regmap = { }; -static int wm9090_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm9090_i2c_probe(struct i2c_client *i2c) { struct wm9090_priv *wm9090; unsigned int reg; @@ -619,7 +616,7 @@ static struct i2c_driver wm9090_i2c_driver = { .driver = { .name = "wm9090", }, - .probe = wm9090_i2c_probe, + .probe_new = wm9090_i2c_probe, .id_table = wm9090_id, }; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 99fe8f316624..d04902ef1d5f 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -368,7 +368,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9705 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9705_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 7515c9d4006e..df9b7980706b 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -692,7 +692,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9712 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9712_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index e0ce32dd4a81..5d2e54e06e30 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1257,7 +1257,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9713 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, }; static int wm9713_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 6cb01a8e08fb..8a2e9771bb50 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -97,13 +97,13 @@ struct wm_adsp_system_config_xm_hdr { __be32 wdma[8]; __be32 build_job_name[3]; __be32 build_job_number; -}; +} __packed; struct wm_halo_system_config_xm_hdr { __be32 halo_heartbeat; __be32 build_job_name[3]; __be32 build_job_number; -}; +} __packed; struct wm_adsp_alg_xm_struct { __be32 magic; @@ -114,13 +114,13 @@ struct wm_adsp_alg_xm_struct { __be32 high_water_mark; __be32 low_water_mark; __be64 smoothed_power; -}; +} __packed; struct wm_adsp_host_buf_coeff_v1 { __be32 host_buf_ptr; /* Host buffer pointer */ __be32 versions; /* Version numbers */ __be32 name[4]; /* The buffer name */ -}; +} __packed; struct wm_adsp_buffer { __be32 buf1_base; /* Base addr of first buffer area */ @@ -141,7 +141,7 @@ struct wm_adsp_buffer { __be32 min_free; /* min free space since stream start */ __be32 blocks_written[2]; /* total blocks written (64 bit) */ __be32 words_written[2]; /* total words written (64 bit) */ -}; +} __packed; struct wm_adsp_compr; @@ -180,7 +180,7 @@ struct wm_adsp_compr { #define WM_ADSP_MIN_FRAGMENTS 1 #define WM_ADSP_MAX_FRAGMENTS 256 -#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * CS_DSP_DATA_WORD_SIZE) +#define WM_ADSP_MIN_FRAGMENT_SIZE (16 * CS_DSP_DATA_WORD_SIZE) #define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * CS_DSP_DATA_WORD_SIZE) #define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7 @@ -296,7 +296,12 @@ static const struct { .num_caps = ARRAY_SIZE(trace_caps), .caps = trace_caps, }, - [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, + [WM_ADSP_FW_SPK_PROT] = { + .file = "spk-prot", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(trace_caps), + .caps = trace_caps, + }, [WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" }, [WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" }, [WM_ADSP_FW_MISC] = { .file = "misc" }, @@ -328,7 +333,7 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); - int ret = 0; + int ret = 1; if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) return 0; @@ -401,7 +406,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, int ret = 0; mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, p, cs_ctl->len); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len); mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; @@ -421,7 +426,7 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, if (copy_from_user(cs_ctl->cache, bytes, size)) ret = -EFAULT; else - ret = cs_dsp_coeff_write_ctrl(cs_ctl, cs_ctl->cache, size); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size); mutex_unlock(&cs_ctl->dsp->pwr_lock); @@ -464,7 +469,7 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, int ret; mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_ctl, p, cs_ctl->len); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len); mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; @@ -481,7 +486,7 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_ctl, cs_ctl->cache, size); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size); if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) ret = -EFAULT; @@ -537,15 +542,20 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) return out; } -static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) +static void wm_adsp_ctl_work(struct work_struct *work) { + struct wm_coeff_ctl *ctl = container_of(work, + struct wm_coeff_ctl, + work); struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; + struct wm_adsp *dsp = container_of(cs_ctl->dsp, + struct wm_adsp, + cs_dsp); struct snd_kcontrol_new *kcontrol; - int ret; kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); if (!kcontrol) - return -ENOMEM; + return; kcontrol->name = ctl->name; kcontrol->info = wm_coeff_info; @@ -571,29 +581,9 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) break; } - ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1); - if (ret < 0) - goto err_kcontrol; - - kfree(kcontrol); - - return 0; + snd_soc_add_component_controls(dsp->component, kcontrol, 1); -err_kcontrol: kfree(kcontrol); - return ret; -} - -static void wm_adsp_ctl_work(struct work_struct *work) -{ - struct wm_coeff_ctl *ctl = container_of(work, - struct wm_coeff_ctl, - work); - struct wm_adsp *dsp = container_of(ctl->cs_ctl->dsp, - struct wm_adsp, - cs_dsp); - - wmfw_add_ctl(dsp, ctl); } static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl) @@ -685,28 +675,21 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - struct cs_dsp_coeff_ctl *cs_ctl; + struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); struct wm_coeff_ctl *ctl; struct snd_kcontrol *kcontrol; char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ret; - cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); - if (!cs_ctl) - return -EINVAL; - - ctl = cs_ctl->priv; - - if (len > cs_ctl->len) - return -EINVAL; - - ret = cs_dsp_coeff_write_ctrl(cs_ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); if (ret) return ret; if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) return 0; + ctl = cs_ctl->priv; + if (dsp->component->name_prefix) snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", dsp->component->name_prefix, ctl->name); @@ -730,16 +713,8 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - struct cs_dsp_coeff_ctl *cs_ctl; - - cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); - if (!cs_ctl) - return -EINVAL; - - if (len > cs_ctl->len) - return -EINVAL; - - return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len); + return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), + 0, buf, len); } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); @@ -759,21 +734,48 @@ static void wm_adsp_release_firmware_files(struct wm_adsp *dsp, } static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, - const struct firmware **firmware, - char **filename, - char *suffix) + const struct firmware **firmware, char **filename, + const char *dir, const char *system_name, + const char *asoc_component_prefix, + const char *filetype) { struct cs_dsp *cs_dsp = &dsp->cs_dsp; + char *s, c; int ret = 0; - *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name, - wm_adsp_fw[dsp->fw].file, suffix); + if (system_name && asoc_component_prefix) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part, + dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name, + asoc_component_prefix, filetype); + else if (system_name) + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part, + dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name, + filetype); + else + *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, dsp->fwf_name, + wm_adsp_fw[dsp->fw].file, filetype); + if (*filename == NULL) return -ENOMEM; - ret = request_firmware(firmware, *filename, cs_dsp->dev); + /* + * Make sure that filename is lower-case and any non alpha-numeric + * characters except full stop and forward slash are replaced with + * hyphens. + */ + s = *filename; + while (*s) { + c = *s; + if (isalnum(c)) + *s = tolower(c); + else if ((c != '.') && (c != '/')) + *s = '-'; + s++; + } + + ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev); if (ret != 0) { - adsp_err(dsp, "Failed to request '%s'\n", *filename); + adsp_dbg(dsp, "Failed to request '%s'\n", *filename); kfree(*filename); *filename = NULL; } @@ -781,21 +783,69 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, return ret; } +static const char *cirrus_dir = "cirrus/"; static int wm_adsp_request_firmware_files(struct wm_adsp *dsp, const struct firmware **wmfw_firmware, char **wmfw_filename, const struct firmware **coeff_firmware, char **coeff_filename) { + const char *system_name = dsp->system_name; + const char *asoc_component_prefix = dsp->component->name_prefix; int ret = 0; - ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw"); - if (ret != 0) - return ret; + if (system_name && asoc_component_prefix) { + if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, + asoc_component_prefix, "wmfw")) { + adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename); + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, system_name, + asoc_component_prefix, "bin"); + return 0; + } + } - wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin"); + if (system_name) { + if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, + NULL, "wmfw")) { + adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename); + if (asoc_component_prefix) + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, system_name, + asoc_component_prefix, "bin"); + + if (!*coeff_firmware) + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, system_name, + NULL, "bin"); + return 0; + } + } - return 0; + if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + "", NULL, NULL, "wmfw")) { + adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename); + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + "", NULL, NULL, "bin"); + return 0; + } + + ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, + cirrus_dir, NULL, NULL, "wmfw"); + if (!ret) { + adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename); + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); + return 0; + } + + adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n", + cirrus_dir, dsp->part, dsp->fwf_name, wm_adsp_fw[dsp->fw].file, + system_name, asoc_component_prefix); + + return -ENOENT; } static int wm_adsp_common_init(struct wm_adsp *dsp) @@ -911,11 +961,12 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, struct wm_adsp *dsp = &dsps[mc->shift - 1]; char preload[32]; - snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); + if (dsp->preloaded == ucontrol->value.integer.value[0]) + return 0; - dsp->preloaded = ucontrol->value.integer.value[0]; + snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); - if (ucontrol->value.integer.value[0]) + if (ucontrol->value.integer.value[0] || dsp->toggle_preload) snd_soc_component_force_enable_pin(component, preload); else snd_soc_component_disable_pin(component, preload); @@ -924,7 +975,14 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, flush_work(&dsp->boot_work); - return 0; + dsp->preloaded = ucontrol->value.integer.value[0]; + + if (dsp->toggle_preload) { + snd_soc_component_disable_pin(component, preload); + snd_soc_dapm_sync(dapm); + } + + return 1; } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); @@ -1380,8 +1438,6 @@ static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) wm_adsp_buffer_clear(buf); - list_add_tail(&buf->list, &dsp->buffer_list); - return buf; } @@ -1398,10 +1454,6 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) return -EINVAL; } - buf = wm_adsp_buffer_alloc(dsp); - if (!buf) - return -ENOMEM; - xmalg = dsp->sys_config_size / sizeof(__be32); addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); @@ -1412,12 +1464,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) return -ENODEV; + buf = wm_adsp_buffer_alloc(dsp); + if (!buf) + return -ENOMEM; + addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); for (i = 0; i < 5; ++i) { ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr, &buf->host_buf_ptr); if (ret < 0) - return ret; + goto err; if (buf->host_buf_ptr) break; @@ -1425,18 +1481,27 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) usleep_range(1000, 2000); } - if (!buf->host_buf_ptr) - return -EIO; + if (!buf->host_buf_ptr) { + ret = -EIO; + goto err; + } buf->host_buf_mem_type = WMFW_ADSP2_XM; ret = wm_adsp_buffer_populate(buf); if (ret < 0) - return ret; + goto err; + + list_add_tail(&buf->list, &dsp->buffer_list); compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; + +err: + kfree(buf); + + return ret; } static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) @@ -1444,11 +1509,12 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) struct wm_adsp_host_buf_coeff_v1 coeff_v1; struct wm_adsp_compr_buf *buf; struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp); - unsigned int version; + unsigned int version = 0; int ret, i; for (i = 0; i < 5; ++i) { - ret = cs_dsp_coeff_read_ctrl(cs_ctl, &coeff_v1, sizeof(coeff_v1)); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1, + min(cs_ctl->len, sizeof(coeff_v1))); if (ret < 0) return ret; @@ -1472,16 +1538,14 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) ret = wm_adsp_buffer_populate(buf); if (ret < 0) - return ret; + goto err; /* * v0 host_buffer coefficients didn't have versioning, so if the * control is one word, assume version 0. */ - if (cs_ctl->len == 4) { - compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); - return 0; - } + if (cs_ctl->len == 4) + goto done; version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK; version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; @@ -1490,7 +1554,8 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) adsp_err(dsp, "Host buffer coeff ver %u > supported version %u\n", version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); - return -EINVAL; + ret = -EINVAL; + goto err; } cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name)); @@ -1498,10 +1563,18 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part, (char *)&coeff_v1.name); +done: + list_add_tail(&buf->list, &dsp->buffer_list); + compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", buf->host_buf_ptr, version); return version; + +err: + kfree(buf); + + return ret; } static int wm_adsp_buffer_init(struct wm_adsp *dsp) @@ -1529,10 +1602,10 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp) if (list_empty(&dsp->buffer_list)) { /* Fall back to legacy support */ ret = wm_adsp_buffer_parse_legacy(dsp); - if (ret) { - adsp_err(dsp, "Failed to parse legacy: %d\n", ret); - goto error; - } + if (ret == -ENODEV) + adsp_info(dsp, "Legacy support not available\n"); + else if (ret) + adsp_warn(dsp, "Failed to parse legacy: %d\n", ret); } return 0; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 0e2f113bd342..375009a65828 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -28,6 +28,7 @@ struct wm_adsp { struct cs_dsp cs_dsp; const char *part; const char *fwf_name; + const char *system_name; struct snd_soc_component *component; unsigned int sys_config_size; @@ -41,6 +42,14 @@ struct wm_adsp { struct list_head compr_list; struct list_head buffer_list; + + /* + * Flag indicating the preloader widget only needs power toggled + * on state change rather than held on for the duration of the + * preload, useful for devices that can retain firmware memory + * across power down. + */ + bool toggle_preload; }; #define WM_ADSP1(wname, num) \ diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 564b78f3cdd0..6c8b1db649b8 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -11,6 +11,7 @@ #include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/pm_runtime.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_type.h> @@ -198,6 +199,7 @@ #define WSA881X_OCP_CTL_TIMER_SEC 2 #define WSA881X_OCP_CTL_TEMP_CELSIUS 25 #define WSA881X_OCP_CTL_POLL_TIMER_SEC 60 +#define WSA881X_PROBE_TIMEOUT 1000 #define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -747,6 +749,10 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc, unsigned int mask = (1 << fls(max)) - 1; int val, ret, min_gain, max_gain; + ret = pm_runtime_resume_and_get(comp->dev); + if (ret < 0 && ret != -EACCES) + return ret; + max_gain = (max - ucontrol->value.integer.value[0]) & mask; /* * Gain has to set incrementally in 4 steps @@ -773,6 +779,9 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc, usleep_range(1000, 1010); } + pm_runtime_mark_last_busy(comp->dev); + pm_runtime_put_autosuspend(comp->dev); + return 1; } @@ -1026,7 +1035,7 @@ static const struct snd_soc_dai_ops wsa881x_dai_ops = { .hw_params = wsa881x_hw_params, .hw_free = wsa881x_hw_free, .mute_stream = wsa881x_digital_mute, - .set_sdw_stream = wsa881x_set_sdw_stream, + .set_stream = wsa881x_set_sdw_stream, }; static struct snd_soc_dai_driver wsa881x_dais[] = { @@ -1055,6 +1064,7 @@ static const struct snd_soc_component_driver wsa881x_component_drv = { .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets), .dapm_routes = wsa881x_audio_map, .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map), + .endianness = 1, }; static int wsa881x_update_status(struct sdw_slave *slave, @@ -1101,6 +1111,7 @@ static int wsa881x_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) { struct wsa881x_priv *wsa881x; + struct device *dev = &pdev->dev; wsa881x = devm_kzalloc(&pdev->dev, sizeof(*wsa881x), GFP_KERNEL); if (!wsa881x) @@ -1132,12 +1143,58 @@ static int wsa881x_probe(struct sdw_slave *pdev, return PTR_ERR(wsa881x->regmap); } + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return devm_snd_soc_register_component(&pdev->dev, &wsa881x_component_drv, wsa881x_dais, ARRAY_SIZE(wsa881x_dais)); } +static int __maybe_unused wsa881x_runtime_suspend(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); + + gpiod_direction_output(wsa881x->sd_n, 0); + + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + + return 0; +} + +static int __maybe_unused wsa881x_runtime_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct regmap *regmap = dev_get_regmap(dev, NULL); + struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); + unsigned long time; + + gpiod_direction_output(wsa881x->sd_n, 1); + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(WSA881X_PROBE_TIMEOUT)); + if (!time) { + dev_err(dev, "Initialization not complete, timed out\n"); + gpiod_direction_output(wsa881x->sd_n, 0); + return -ETIMEDOUT; + } + + regcache_cache_only(regmap, false); + regcache_sync(regmap); + + return 0; +} + +static const struct dev_pm_ops wsa881x_pm_ops = { + SET_RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL) +}; + static const struct sdw_device_id wsa881x_slave_id[] = { SDW_SLAVE_ENTRY(0x0217, 0x2010, 0), SDW_SLAVE_ENTRY(0x0217, 0x2110, 0), @@ -1151,6 +1208,7 @@ static struct sdw_driver wsa881x_codec_driver = { .id_table = wsa881x_slave_id, .driver = { .name = "wsa881x-codec", + .pm = &wsa881x_pm_ops, } }; module_sdw_driver(wsa881x_codec_driver); diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c new file mode 100644 index 000000000000..c7b10bbfba7e --- /dev/null +++ b/sound/soc/codecs/wsa883x.c @@ -0,0 +1,1485 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ + +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/printk.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc-dapm.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#define WSA883X_BASE 0x3000 +#define WSA883X_ANA_BG_TSADC_BASE (WSA883X_BASE + 0x00000001) +#define WSA883X_REF_CTRL (WSA883X_ANA_BG_TSADC_BASE + 0x0000) +#define WSA883X_TEST_CTL_0 (WSA883X_ANA_BG_TSADC_BASE + 0x0001) +#define WSA883X_BIAS_0 (WSA883X_ANA_BG_TSADC_BASE + 0x0002) +#define WSA883X_OP_CTL (WSA883X_ANA_BG_TSADC_BASE + 0x0003) +#define WSA883X_IREF_CTL (WSA883X_ANA_BG_TSADC_BASE + 0x0004) +#define WSA883X_ISENS_CTL (WSA883X_ANA_BG_TSADC_BASE + 0x0005) +#define WSA883X_CLK_CTL (WSA883X_ANA_BG_TSADC_BASE + 0x0006) +#define WSA883X_TEST_CTL_1 (WSA883X_ANA_BG_TSADC_BASE + 0x0007) +#define WSA883X_BIAS_1 (WSA883X_ANA_BG_TSADC_BASE + 0x0008) +#define WSA883X_ADC_CTL (WSA883X_ANA_BG_TSADC_BASE + 0x0009) +#define WSA883X_DOUT_MSB (WSA883X_ANA_BG_TSADC_BASE + 0x000A) +#define WSA883X_DOUT_LSB (WSA883X_ANA_BG_TSADC_BASE + 0x000B) +#define WSA883X_VBAT_SNS (WSA883X_ANA_BG_TSADC_BASE + 0x000C) +#define WSA883X_ITRIM_CODE (WSA883X_ANA_BG_TSADC_BASE + 0x000D) + +#define WSA883X_ANA_IVSENSE_BASE (WSA883X_BASE + 0x0000000F) +#define WSA883X_EN (WSA883X_ANA_IVSENSE_BASE + 0x0000) +#define WSA883X_OVERRIDE1 (WSA883X_ANA_IVSENSE_BASE + 0x0001) +#define WSA883X_OVERRIDE2 (WSA883X_ANA_IVSENSE_BASE + 0x0002) +#define WSA883X_VSENSE1 (WSA883X_ANA_IVSENSE_BASE + 0x0003) +#define WSA883X_ISENSE1 (WSA883X_ANA_IVSENSE_BASE + 0x0004) +#define WSA883X_ISENSE2 (WSA883X_ANA_IVSENSE_BASE + 0x0005) +#define WSA883X_ISENSE_CAL (WSA883X_ANA_IVSENSE_BASE + 0x0006) +#define WSA883X_MISC (WSA883X_ANA_IVSENSE_BASE + 0x0007) +#define WSA883X_ADC_0 (WSA883X_ANA_IVSENSE_BASE + 0x0008) +#define WSA883X_ADC_1 (WSA883X_ANA_IVSENSE_BASE + 0x0009) +#define WSA883X_ADC_2 (WSA883X_ANA_IVSENSE_BASE + 0x000A) +#define WSA883X_ADC_3 (WSA883X_ANA_IVSENSE_BASE + 0x000B) +#define WSA883X_ADC_4 (WSA883X_ANA_IVSENSE_BASE + 0x000C) +#define WSA883X_ADC_5 (WSA883X_ANA_IVSENSE_BASE + 0x000D) +#define WSA883X_ADC_6 (WSA883X_ANA_IVSENSE_BASE + 0x000E) +#define WSA883X_ADC_7 (WSA883X_ANA_IVSENSE_BASE + 0x000F) +#define WSA883X_STATUS (WSA883X_ANA_IVSENSE_BASE + 0x0010) + +#define WSA883X_ANA_SPK_TOP_BASE (WSA883X_BASE + 0x00000025) +#define WSA883X_DAC_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0000) +#define WSA883X_DAC_EN_DEBUG_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0001) +#define WSA883X_DAC_OPAMP_BIAS1_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0002) +#define WSA883X_DAC_OPAMP_BIAS2_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0003) +#define WSA883X_DAC_VCM_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0004) +#define WSA883X_DAC_VOLTAGE_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0005) +#define WSA883X_ATEST1_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0006) +#define WSA883X_ATEST2_REG (WSA883X_ANA_SPK_TOP_BASE + 0x0007) +#define WSA883X_SPKR_TOP_BIAS_REG1 (WSA883X_ANA_SPK_TOP_BASE + 0x0008) +#define WSA883X_SPKR_TOP_BIAS_REG2 (WSA883X_ANA_SPK_TOP_BASE + 0x0009) +#define WSA883X_SPKR_TOP_BIAS_REG3 (WSA883X_ANA_SPK_TOP_BASE + 0x000A) +#define WSA883X_SPKR_TOP_BIAS_REG4 (WSA883X_ANA_SPK_TOP_BASE + 0x000B) +#define WSA883X_SPKR_CLIP_DET_REG (WSA883X_ANA_SPK_TOP_BASE + 0x000C) +#define WSA883X_SPKR_DRV_LF_BLK_EN (WSA883X_ANA_SPK_TOP_BASE + 0x000D) +#define WSA883X_SPKR_DRV_LF_EN (WSA883X_ANA_SPK_TOP_BASE + 0x000E) +#define WSA883X_SPKR_DRV_LF_MASK_DCC_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x000F) +#define WSA883X_SPKR_DRV_LF_MISC_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0010) +#define WSA883X_SPKR_DRV_LF_REG_GAIN (WSA883X_ANA_SPK_TOP_BASE + 0x0011) +#define WSA883X_SPKR_DRV_OS_CAL_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0012) +#define WSA883X_SPKR_DRV_OS_CAL_CTL1 (WSA883X_ANA_SPK_TOP_BASE + 0x0013) +#define WSA883X_SPKR_PWM_CLK_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0014) +#define WSA883X_SPKR_PWM_FREQ_SEL_MASK BIT(3) +#define WSA883X_SPKR_PWM_FREQ_F300KHZ 0 +#define WSA883X_SPKR_PWM_FREQ_F600KHZ 1 +#define WSA883X_SPKR_PDRV_HS_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0015) +#define WSA883X_SPKR_PDRV_LS_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0016) +#define WSA883X_SPKR_PWRSTG_DBG (WSA883X_ANA_SPK_TOP_BASE + 0x0017) +#define WSA883X_SPKR_OCP_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0018) +#define WSA883X_SPKR_BBM_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0019) +#define WSA883X_PA_STATUS0 (WSA883X_ANA_SPK_TOP_BASE + 0x001A) +#define WSA883X_PA_STATUS1 (WSA883X_ANA_SPK_TOP_BASE + 0x001B) +#define WSA883X_PA_STATUS2 (WSA883X_ANA_SPK_TOP_BASE + 0x001C) + +#define WSA883X_ANA_BOOST_BASE (WSA883X_BASE + 0x00000043) +#define WSA883X_EN_CTRL (WSA883X_ANA_BOOST_BASE + 0x0000) +#define WSA883X_CURRENT_LIMIT (WSA883X_ANA_BOOST_BASE + 0x0001) +#define WSA883X_IBIAS1 (WSA883X_ANA_BOOST_BASE + 0x0002) +#define WSA883X_IBIAS2 (WSA883X_ANA_BOOST_BASE + 0x0003) +#define WSA883X_IBIAS3 (WSA883X_ANA_BOOST_BASE + 0x0004) +#define WSA883X_LDO_PROG (WSA883X_ANA_BOOST_BASE + 0x0005) +#define WSA883X_STABILITY_CTRL1 (WSA883X_ANA_BOOST_BASE + 0x0006) +#define WSA883X_STABILITY_CTRL2 (WSA883X_ANA_BOOST_BASE + 0x0007) +#define WSA883X_PWRSTAGE_CTRL1 (WSA883X_ANA_BOOST_BASE + 0x0008) +#define WSA883X_PWRSTAGE_CTRL2 (WSA883X_ANA_BOOST_BASE + 0x0009) +#define WSA883X_BYPASS_1 (WSA883X_ANA_BOOST_BASE + 0x000A) +#define WSA883X_BYPASS_2 (WSA883X_ANA_BOOST_BASE + 0x000B) +#define WSA883X_ZX_CTRL_1 (WSA883X_ANA_BOOST_BASE + 0x000C) +#define WSA883X_ZX_CTRL_2 (WSA883X_ANA_BOOST_BASE + 0x000D) +#define WSA883X_MISC1 (WSA883X_ANA_BOOST_BASE + 0x000E) +#define WSA883X_MISC2 (WSA883X_ANA_BOOST_BASE + 0x000F) +#define WSA883X_GMAMP_SUP1 (WSA883X_ANA_BOOST_BASE + 0x0010) +#define WSA883X_PWRSTAGE_CTRL3 (WSA883X_ANA_BOOST_BASE + 0x0011) +#define WSA883X_PWRSTAGE_CTRL4 (WSA883X_ANA_BOOST_BASE + 0x0012) +#define WSA883X_TEST1 (WSA883X_ANA_BOOST_BASE + 0x0013) +#define WSA883X_SPARE1 (WSA883X_ANA_BOOST_BASE + 0x0014) +#define WSA883X_SPARE2 (WSA883X_ANA_BOOST_BASE + 0x0015) + +#define WSA883X_ANA_PON_LDOL_BASE (WSA883X_BASE + 0x00000059) +#define WSA883X_PON_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0000) +#define WSA883X_PON_CLT_1 (WSA883X_ANA_PON_LDOL_BASE + 0x0001) +#define WSA883X_PON_CTL_2 (WSA883X_ANA_PON_LDOL_BASE + 0x0002) +#define WSA883X_PON_CTL_3 (WSA883X_ANA_PON_LDOL_BASE + 0x0003) +#define WSA883X_CKWD_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0004) +#define WSA883X_CKWD_CTL_1 (WSA883X_ANA_PON_LDOL_BASE + 0x0005) +#define WSA883X_CKWD_CTL_2 (WSA883X_ANA_PON_LDOL_BASE + 0x0006) +#define WSA883X_CKSK_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0007) +#define WSA883X_PADSW_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0008) +#define WSA883X_TEST_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0009) +#define WSA883X_TEST_1 (WSA883X_ANA_PON_LDOL_BASE + 0x000A) +#define WSA883X_STATUS_0 (WSA883X_ANA_PON_LDOL_BASE + 0x000B) +#define WSA883X_STATUS_1 (WSA883X_ANA_PON_LDOL_BASE + 0x000C) + +#define WSA883X_DIG_CTRL_BASE (WSA883X_BASE + 0x00000400) +#define WSA883X_CHIP_ID0 (WSA883X_DIG_CTRL_BASE + 0x0001) +#define WSA883X_CHIP_ID1 (WSA883X_DIG_CTRL_BASE + 0x0002) +#define WSA883X_CHIP_ID2 (WSA883X_DIG_CTRL_BASE + 0x0003) +#define WSA883X_CHIP_ID3 (WSA883X_DIG_CTRL_BASE + 0x0004) +#define WSA883X_BUS_ID (WSA883X_DIG_CTRL_BASE + 0x0005) +#define WSA883X_CDC_RST_CTL (WSA883X_DIG_CTRL_BASE + 0x0006) +#define WSA883X_TOP_CLK_CFG (WSA883X_DIG_CTRL_BASE + 0x0007) +#define WSA883X_CDC_PATH_MODE (WSA883X_DIG_CTRL_BASE + 0x0008) +#define WSA883X_RXD_MODE_MASK BIT(1) +#define WSA883X_RXD_MODE_NORMAL 0 +#define WSA883X_RXD_MODE_HIFI 1 +#define WSA883X_CDC_CLK_CTL (WSA883X_DIG_CTRL_BASE + 0x0009) +#define WSA883X_SWR_RESET_EN (WSA883X_DIG_CTRL_BASE + 0x000A) +#define WSA883X_RESET_CTL (WSA883X_DIG_CTRL_BASE + 0x000B) +#define WSA883X_PA_FSM_CTL (WSA883X_DIG_CTRL_BASE + 0x0010) +#define WSA883X_GLOBAL_PA_EN_MASK BIT(0) +#define WSA883X_GLOBAL_PA_ENABLE 1 +#define WSA883X_PA_FSM_TIMER0 (WSA883X_DIG_CTRL_BASE + 0x0011) +#define WSA883X_PA_FSM_TIMER1 (WSA883X_DIG_CTRL_BASE + 0x0012) +#define WSA883X_PA_FSM_STA (WSA883X_DIG_CTRL_BASE + 0x0013) +#define WSA883X_PA_FSM_ERR_COND (WSA883X_DIG_CTRL_BASE + 0x0014) +#define WSA883X_PA_FSM_MSK (WSA883X_DIG_CTRL_BASE + 0x0015) +#define WSA883X_PA_FSM_BYP (WSA883X_DIG_CTRL_BASE + 0x0016) +#define WSA883X_PA_FSM_DBG (WSA883X_DIG_CTRL_BASE + 0x0017) +#define WSA883X_TADC_VALUE_CTL (WSA883X_DIG_CTRL_BASE + 0x0020) +#define WSA883X_TEMP_DETECT_CTL (WSA883X_DIG_CTRL_BASE + 0x0021) +#define WSA883X_TEMP_MSB (WSA883X_DIG_CTRL_BASE + 0x0022) +#define WSA883X_TEMP_LSB (WSA883X_DIG_CTRL_BASE + 0x0023) +#define WSA883X_TEMP_CONFIG0 (WSA883X_DIG_CTRL_BASE + 0x0024) +#define WSA883X_TEMP_CONFIG1 (WSA883X_DIG_CTRL_BASE + 0x0025) +#define WSA883X_VBAT_ADC_FLT_CTL (WSA883X_DIG_CTRL_BASE + 0x0026) +#define WSA883X_VBAT_ADC_FLT_EN_MASK BIT(0) +#define WSA883X_VBAT_ADC_COEF_SEL_MASK GENMASK(3, 1) +#define WSA883X_VBAT_ADC_COEF_F_1DIV2 0x0 +#define WSA883X_VBAT_ADC_COEF_F_1DIV16 0x3 +#define WSA883X_VBAT_DIN_MSB (WSA883X_DIG_CTRL_BASE + 0x0027) +#define WSA883X_VBAT_DIN_LSB (WSA883X_DIG_CTRL_BASE + 0x0028) +#define WSA883X_VBAT_DOUT (WSA883X_DIG_CTRL_BASE + 0x0029) +#define WSA883X_SDM_PDM9_LSB (WSA883X_DIG_CTRL_BASE + 0x002A) +#define WSA883X_SDM_PDM9_MSB (WSA883X_DIG_CTRL_BASE + 0x002B) +#define WSA883X_CDC_RX_CTL (WSA883X_DIG_CTRL_BASE + 0x0030) +#define WSA883X_CDC_SPK_DSM_A1_0 (WSA883X_DIG_CTRL_BASE + 0x0031) +#define WSA883X_CDC_SPK_DSM_A1_1 (WSA883X_DIG_CTRL_BASE + 0x0032) +#define WSA883X_CDC_SPK_DSM_A2_0 (WSA883X_DIG_CTRL_BASE + 0x0033) +#define WSA883X_CDC_SPK_DSM_A2_1 (WSA883X_DIG_CTRL_BASE + 0x0034) +#define WSA883X_CDC_SPK_DSM_A3_0 (WSA883X_DIG_CTRL_BASE + 0x0035) +#define WSA883X_CDC_SPK_DSM_A3_1 (WSA883X_DIG_CTRL_BASE + 0x0036) +#define WSA883X_CDC_SPK_DSM_A4_0 (WSA883X_DIG_CTRL_BASE + 0x0037) +#define WSA883X_CDC_SPK_DSM_A4_1 (WSA883X_DIG_CTRL_BASE + 0x0038) +#define WSA883X_CDC_SPK_DSM_A5_0 (WSA883X_DIG_CTRL_BASE + 0x0039) +#define WSA883X_CDC_SPK_DSM_A5_1 (WSA883X_DIG_CTRL_BASE + 0x003A) +#define WSA883X_CDC_SPK_DSM_A6_0 (WSA883X_DIG_CTRL_BASE + 0x003B) +#define WSA883X_CDC_SPK_DSM_A7_0 (WSA883X_DIG_CTRL_BASE + 0x003C) +#define WSA883X_CDC_SPK_DSM_C_0 (WSA883X_DIG_CTRL_BASE + 0x003D) +#define WSA883X_CDC_SPK_DSM_C_1 (WSA883X_DIG_CTRL_BASE + 0x003E) +#define WSA883X_CDC_SPK_DSM_C_2 (WSA883X_DIG_CTRL_BASE + 0x003F) +#define WSA883X_CDC_SPK_DSM_C_3 (WSA883X_DIG_CTRL_BASE + 0x0040) +#define WSA883X_CDC_SPK_DSM_R1 (WSA883X_DIG_CTRL_BASE + 0x0041) +#define WSA883X_CDC_SPK_DSM_R2 (WSA883X_DIG_CTRL_BASE + 0x0042) +#define WSA883X_CDC_SPK_DSM_R3 (WSA883X_DIG_CTRL_BASE + 0x0043) +#define WSA883X_CDC_SPK_DSM_R4 (WSA883X_DIG_CTRL_BASE + 0x0044) +#define WSA883X_CDC_SPK_DSM_R5 (WSA883X_DIG_CTRL_BASE + 0x0045) +#define WSA883X_CDC_SPK_DSM_R6 (WSA883X_DIG_CTRL_BASE + 0x0046) +#define WSA883X_CDC_SPK_DSM_R7 (WSA883X_DIG_CTRL_BASE + 0x0047) +#define WSA883X_CDC_SPK_GAIN_PDM_0 (WSA883X_DIG_CTRL_BASE + 0x0048) +#define WSA883X_CDC_SPK_GAIN_PDM_1 (WSA883X_DIG_CTRL_BASE + 0x0049) +#define WSA883X_CDC_SPK_GAIN_PDM_2 (WSA883X_DIG_CTRL_BASE + 0x004A) +#define WSA883X_PDM_WD_CTL (WSA883X_DIG_CTRL_BASE + 0x004B) +#define WSA883X_PDM_EN_MASK BIT(0) +#define WSA883X_PDM_ENABLE BIT(0) +#define WSA883X_DEM_BYPASS_DATA0 (WSA883X_DIG_CTRL_BASE + 0x004C) +#define WSA883X_DEM_BYPASS_DATA1 (WSA883X_DIG_CTRL_BASE + 0x004D) +#define WSA883X_DEM_BYPASS_DATA2 (WSA883X_DIG_CTRL_BASE + 0x004E) +#define WSA883X_DEM_BYPASS_DATA3 (WSA883X_DIG_CTRL_BASE + 0x004F) +#define WSA883X_WAVG_CTL (WSA883X_DIG_CTRL_BASE + 0x0050) +#define WSA883X_WAVG_LRA_PER_0 (WSA883X_DIG_CTRL_BASE + 0x0051) +#define WSA883X_WAVG_LRA_PER_1 (WSA883X_DIG_CTRL_BASE + 0x0052) +#define WSA883X_WAVG_DELTA_THETA_0 (WSA883X_DIG_CTRL_BASE + 0x0053) +#define WSA883X_WAVG_DELTA_THETA_1 (WSA883X_DIG_CTRL_BASE + 0x0054) +#define WSA883X_WAVG_DIRECT_AMP_0 (WSA883X_DIG_CTRL_BASE + 0x0055) +#define WSA883X_WAVG_DIRECT_AMP_1 (WSA883X_DIG_CTRL_BASE + 0x0056) +#define WSA883X_WAVG_PTRN_AMP0_0 (WSA883X_DIG_CTRL_BASE + 0x0057) +#define WSA883X_WAVG_PTRN_AMP0_1 (WSA883X_DIG_CTRL_BASE + 0x0058) +#define WSA883X_WAVG_PTRN_AMP1_0 (WSA883X_DIG_CTRL_BASE + 0x0059) +#define WSA883X_WAVG_PTRN_AMP1_1 (WSA883X_DIG_CTRL_BASE + 0x005A) +#define WSA883X_WAVG_PTRN_AMP2_0 (WSA883X_DIG_CTRL_BASE + 0x005B) +#define WSA883X_WAVG_PTRN_AMP2_1 (WSA883X_DIG_CTRL_BASE + 0x005C) +#define WSA883X_WAVG_PTRN_AMP3_0 (WSA883X_DIG_CTRL_BASE + 0x005D) +#define WSA883X_WAVG_PTRN_AMP3_1 (WSA883X_DIG_CTRL_BASE + 0x005E) +#define WSA883X_WAVG_PTRN_AMP4_0 (WSA883X_DIG_CTRL_BASE + 0x005F) +#define WSA883X_WAVG_PTRN_AMP4_1 (WSA883X_DIG_CTRL_BASE + 0x0060) +#define WSA883X_WAVG_PTRN_AMP5_0 (WSA883X_DIG_CTRL_BASE + 0x0061) +#define WSA883X_WAVG_PTRN_AMP5_1 (WSA883X_DIG_CTRL_BASE + 0x0062) +#define WSA883X_WAVG_PTRN_AMP6_0 (WSA883X_DIG_CTRL_BASE + 0x0063) +#define WSA883X_WAVG_PTRN_AMP6_1 (WSA883X_DIG_CTRL_BASE + 0x0064) +#define WSA883X_WAVG_PTRN_AMP7_0 (WSA883X_DIG_CTRL_BASE + 0x0065) +#define WSA883X_WAVG_PTRN_AMP7_1 (WSA883X_DIG_CTRL_BASE + 0x0066) +#define WSA883X_WAVG_PER_0_1 (WSA883X_DIG_CTRL_BASE + 0x0067) +#define WSA883X_WAVG_PER_2_3 (WSA883X_DIG_CTRL_BASE + 0x0068) +#define WSA883X_WAVG_PER_4_5 (WSA883X_DIG_CTRL_BASE + 0x0069) +#define WSA883X_WAVG_PER_6_7 (WSA883X_DIG_CTRL_BASE + 0x006A) +#define WSA883X_WAVG_STA (WSA883X_DIG_CTRL_BASE + 0x006B) +#define WSA883X_DRE_CTL_0 (WSA883X_DIG_CTRL_BASE + 0x006C) +#define WSA883X_DRE_OFFSET_MASK GENMASK(2, 0) +#define WSA883X_DRE_PROG_DELAY_MASK GENMASK(7, 4) +#define WSA883X_DRE_CTL_1 (WSA883X_DIG_CTRL_BASE + 0x006D) +#define WSA883X_DRE_GAIN_EN_MASK BIT(0) +#define WSA883X_DRE_GAIN_FROM_CSR 1 +#define WSA883X_DRE_IDLE_DET_CTL (WSA883X_DIG_CTRL_BASE + 0x006E) +#define WSA883X_CLSH_CTL_0 (WSA883X_DIG_CTRL_BASE + 0x0070) +#define WSA883X_CLSH_CTL_1 (WSA883X_DIG_CTRL_BASE + 0x0071) +#define WSA883X_CLSH_V_HD_PA (WSA883X_DIG_CTRL_BASE + 0x0072) +#define WSA883X_CLSH_V_PA_MIN (WSA883X_DIG_CTRL_BASE + 0x0073) +#define WSA883X_CLSH_OVRD_VAL (WSA883X_DIG_CTRL_BASE + 0x0074) +#define WSA883X_CLSH_HARD_MAX (WSA883X_DIG_CTRL_BASE + 0x0075) +#define WSA883X_CLSH_SOFT_MAX (WSA883X_DIG_CTRL_BASE + 0x0076) +#define WSA883X_CLSH_SIG_DP (WSA883X_DIG_CTRL_BASE + 0x0077) +#define WSA883X_TAGC_CTL (WSA883X_DIG_CTRL_BASE + 0x0078) +#define WSA883X_TAGC_TIME (WSA883X_DIG_CTRL_BASE + 0x0079) +#define WSA883X_TAGC_E2E_GAIN (WSA883X_DIG_CTRL_BASE + 0x007A) +#define WSA883X_TAGC_FORCE_VAL (WSA883X_DIG_CTRL_BASE + 0x007B) +#define WSA883X_VAGC_CTL (WSA883X_DIG_CTRL_BASE + 0x007C) +#define WSA883X_VAGC_TIME (WSA883X_DIG_CTRL_BASE + 0x007D) +#define WSA883X_VAGC_ATTN_LVL_1_2 (WSA883X_DIG_CTRL_BASE + 0x007E) +#define WSA883X_VAGC_ATTN_LVL_3 (WSA883X_DIG_CTRL_BASE + 0x007F) +#define WSA883X_INTR_MODE (WSA883X_DIG_CTRL_BASE + 0x0080) +#define WSA883X_INTR_MASK0 (WSA883X_DIG_CTRL_BASE + 0x0081) +#define WSA883X_INTR_MASK1 (WSA883X_DIG_CTRL_BASE + 0x0082) +#define WSA883X_INTR_STATUS0 (WSA883X_DIG_CTRL_BASE + 0x0083) +#define WSA883X_INTR_STATUS1 (WSA883X_DIG_CTRL_BASE + 0x0084) +#define WSA883X_INTR_CLEAR0 (WSA883X_DIG_CTRL_BASE + 0x0085) +#define WSA883X_INTR_CLEAR1 (WSA883X_DIG_CTRL_BASE + 0x0086) +#define WSA883X_INTR_LEVEL0 (WSA883X_DIG_CTRL_BASE + 0x0087) +#define WSA883X_INTR_LEVEL1 (WSA883X_DIG_CTRL_BASE + 0x0088) +#define WSA883X_INTR_SET0 (WSA883X_DIG_CTRL_BASE + 0x0089) +#define WSA883X_INTR_SET1 (WSA883X_DIG_CTRL_BASE + 0x008A) +#define WSA883X_INTR_TEST0 (WSA883X_DIG_CTRL_BASE + 0x008B) +#define WSA883X_INTR_TEST1 (WSA883X_DIG_CTRL_BASE + 0x008C) +#define WSA883X_OTP_CTRL0 (WSA883X_DIG_CTRL_BASE + 0x0090) +#define WSA883X_OTP_CTRL1 (WSA883X_DIG_CTRL_BASE + 0x0091) +#define WSA883X_HDRIVE_CTL_GROUP1 (WSA883X_DIG_CTRL_BASE + 0x0092) +#define WSA883X_PIN_CTL (WSA883X_DIG_CTRL_BASE + 0x0093) +#define WSA883X_PIN_CTL_OE (WSA883X_DIG_CTRL_BASE + 0x0094) +#define WSA883X_PIN_WDATA_IOPAD (WSA883X_DIG_CTRL_BASE + 0x0095) +#define WSA883X_PIN_STATUS (WSA883X_DIG_CTRL_BASE + 0x0096) +#define WSA883X_I2C_SLAVE_CTL (WSA883X_DIG_CTRL_BASE + 0x0097) +#define WSA883X_PDM_TEST_MODE (WSA883X_DIG_CTRL_BASE + 0x00A0) +#define WSA883X_ATE_TEST_MODE (WSA883X_DIG_CTRL_BASE + 0x00A1) +#define WSA883X_DIG_DEBUG_MODE (WSA883X_DIG_CTRL_BASE + 0x00A3) +#define WSA883X_DIG_DEBUG_SEL (WSA883X_DIG_CTRL_BASE + 0x00A4) +#define WSA883X_DIG_DEBUG_EN (WSA883X_DIG_CTRL_BASE + 0x00A5) +#define WSA883X_SWR_HM_TEST0 (WSA883X_DIG_CTRL_BASE + 0x00A6) +#define WSA883X_SWR_HM_TEST1 (WSA883X_DIG_CTRL_BASE + 0x00A7) +#define WSA883X_SWR_PAD_CTL (WSA883X_DIG_CTRL_BASE + 0x00A8) +#define WSA883X_TADC_DETECT_DBG_CTL (WSA883X_DIG_CTRL_BASE + 0x00A9) +#define WSA883X_TADC_DEBUG_MSB (WSA883X_DIG_CTRL_BASE + 0x00AA) +#define WSA883X_TADC_DEBUG_LSB (WSA883X_DIG_CTRL_BASE + 0x00AB) +#define WSA883X_SAMPLE_EDGE_SEL (WSA883X_DIG_CTRL_BASE + 0x00AC) +#define WSA883X_SWR_EDGE_SEL (WSA883X_DIG_CTRL_BASE + 0x00AD) +#define WSA883X_TEST_MODE_CTL (WSA883X_DIG_CTRL_BASE + 0x00AE) +#define WSA883X_IOPAD_CTL (WSA883X_DIG_CTRL_BASE + 0x00AF) +#define WSA883X_ANA_CSR_DBG_ADD (WSA883X_DIG_CTRL_BASE + 0x00B0) +#define WSA883X_ANA_CSR_DBG_CTL (WSA883X_DIG_CTRL_BASE + 0x00B1) +#define WSA883X_SPARE_R (WSA883X_DIG_CTRL_BASE + 0x00BC) +#define WSA883X_SPARE_0 (WSA883X_DIG_CTRL_BASE + 0x00BD) +#define WSA883X_SPARE_1 (WSA883X_DIG_CTRL_BASE + 0x00BE) +#define WSA883X_SPARE_2 (WSA883X_DIG_CTRL_BASE + 0x00BF) +#define WSA883X_SCODE (WSA883X_DIG_CTRL_BASE + 0x00C0) + +#define WSA883X_DIG_TRIM_BASE (WSA883X_BASE + 0x00000500) +#define WSA883X_OTP_REG_0 (WSA883X_DIG_TRIM_BASE + 0x0080) +#define WSA883X_ID_MASK GENMASK(3, 0) +#define WSA883X_OTP_REG_1 (WSA883X_DIG_TRIM_BASE + 0x0081) +#define WSA883X_OTP_REG_2 (WSA883X_DIG_TRIM_BASE + 0x0082) +#define WSA883X_OTP_REG_3 (WSA883X_DIG_TRIM_BASE + 0x0083) +#define WSA883X_OTP_REG_4 (WSA883X_DIG_TRIM_BASE + 0x0084) +#define WSA883X_OTP_REG_5 (WSA883X_DIG_TRIM_BASE + 0x0085) +#define WSA883X_OTP_REG_6 (WSA883X_DIG_TRIM_BASE + 0x0086) +#define WSA883X_OTP_REG_7 (WSA883X_DIG_TRIM_BASE + 0x0087) +#define WSA883X_OTP_REG_8 (WSA883X_DIG_TRIM_BASE + 0x0088) +#define WSA883X_OTP_REG_9 (WSA883X_DIG_TRIM_BASE + 0x0089) +#define WSA883X_OTP_REG_10 (WSA883X_DIG_TRIM_BASE + 0x008A) +#define WSA883X_OTP_REG_11 (WSA883X_DIG_TRIM_BASE + 0x008B) +#define WSA883X_OTP_REG_12 (WSA883X_DIG_TRIM_BASE + 0x008C) +#define WSA883X_OTP_REG_13 (WSA883X_DIG_TRIM_BASE + 0x008D) +#define WSA883X_OTP_REG_14 (WSA883X_DIG_TRIM_BASE + 0x008E) +#define WSA883X_OTP_REG_15 (WSA883X_DIG_TRIM_BASE + 0x008F) +#define WSA883X_OTP_REG_16 (WSA883X_DIG_TRIM_BASE + 0x0090) +#define WSA883X_OTP_REG_17 (WSA883X_DIG_TRIM_BASE + 0x0091) +#define WSA883X_OTP_REG_18 (WSA883X_DIG_TRIM_BASE + 0x0092) +#define WSA883X_OTP_REG_19 (WSA883X_DIG_TRIM_BASE + 0x0093) +#define WSA883X_OTP_REG_20 (WSA883X_DIG_TRIM_BASE + 0x0094) +#define WSA883X_OTP_REG_21 (WSA883X_DIG_TRIM_BASE + 0x0095) +#define WSA883X_OTP_REG_22 (WSA883X_DIG_TRIM_BASE + 0x0096) +#define WSA883X_OTP_REG_23 (WSA883X_DIG_TRIM_BASE + 0x0097) +#define WSA883X_OTP_REG_24 (WSA883X_DIG_TRIM_BASE + 0x0098) +#define WSA883X_OTP_REG_25 (WSA883X_DIG_TRIM_BASE + 0x0099) +#define WSA883X_OTP_REG_26 (WSA883X_DIG_TRIM_BASE + 0x009A) +#define WSA883X_OTP_REG_27 (WSA883X_DIG_TRIM_BASE + 0x009B) +#define WSA883X_OTP_REG_28 (WSA883X_DIG_TRIM_BASE + 0x009C) +#define WSA883X_OTP_REG_29 (WSA883X_DIG_TRIM_BASE + 0x009D) +#define WSA883X_OTP_REG_30 (WSA883X_DIG_TRIM_BASE + 0x009E) +#define WSA883X_OTP_REG_31 (WSA883X_DIG_TRIM_BASE + 0x009F) +#define WSA883X_OTP_REG_32 (WSA883X_DIG_TRIM_BASE + 0x00A0) +#define WSA883X_OTP_REG_33 (WSA883X_DIG_TRIM_BASE + 0x00A1) +#define WSA883X_OTP_REG_34 (WSA883X_DIG_TRIM_BASE + 0x00A2) +#define WSA883X_OTP_REG_35 (WSA883X_DIG_TRIM_BASE + 0x00A3) +#define WSA883X_OTP_REG_63 (WSA883X_DIG_TRIM_BASE + 0x00BF) + +#define WSA883X_DIG_EMEM_BASE (WSA883X_BASE + 0x000005C0) +#define WSA883X_EMEM_0 (WSA883X_DIG_EMEM_BASE + 0x0000) +#define WSA883X_EMEM_1 (WSA883X_DIG_EMEM_BASE + 0x0001) +#define WSA883X_EMEM_2 (WSA883X_DIG_EMEM_BASE + 0x0002) +#define WSA883X_EMEM_3 (WSA883X_DIG_EMEM_BASE + 0x0003) +#define WSA883X_EMEM_4 (WSA883X_DIG_EMEM_BASE + 0x0004) +#define WSA883X_EMEM_5 (WSA883X_DIG_EMEM_BASE + 0x0005) +#define WSA883X_EMEM_6 (WSA883X_DIG_EMEM_BASE + 0x0006) +#define WSA883X_EMEM_7 (WSA883X_DIG_EMEM_BASE + 0x0007) +#define WSA883X_EMEM_8 (WSA883X_DIG_EMEM_BASE + 0x0008) +#define WSA883X_EMEM_9 (WSA883X_DIG_EMEM_BASE + 0x0009) +#define WSA883X_EMEM_10 (WSA883X_DIG_EMEM_BASE + 0x000A) +#define WSA883X_EMEM_11 (WSA883X_DIG_EMEM_BASE + 0x000B) +#define WSA883X_EMEM_12 (WSA883X_DIG_EMEM_BASE + 0x000C) +#define WSA883X_EMEM_13 (WSA883X_DIG_EMEM_BASE + 0x000D) +#define WSA883X_EMEM_14 (WSA883X_DIG_EMEM_BASE + 0x000E) +#define WSA883X_EMEM_15 (WSA883X_DIG_EMEM_BASE + 0x000F) +#define WSA883X_EMEM_16 (WSA883X_DIG_EMEM_BASE + 0x0010) +#define WSA883X_EMEM_17 (WSA883X_DIG_EMEM_BASE + 0x0011) +#define WSA883X_EMEM_18 (WSA883X_DIG_EMEM_BASE + 0x0012) +#define WSA883X_EMEM_19 (WSA883X_DIG_EMEM_BASE + 0x0013) +#define WSA883X_EMEM_20 (WSA883X_DIG_EMEM_BASE + 0x0014) +#define WSA883X_EMEM_21 (WSA883X_DIG_EMEM_BASE + 0x0015) +#define WSA883X_EMEM_22 (WSA883X_DIG_EMEM_BASE + 0x0016) +#define WSA883X_EMEM_23 (WSA883X_DIG_EMEM_BASE + 0x0017) +#define WSA883X_EMEM_24 (WSA883X_DIG_EMEM_BASE + 0x0018) +#define WSA883X_EMEM_25 (WSA883X_DIG_EMEM_BASE + 0x0019) +#define WSA883X_EMEM_26 (WSA883X_DIG_EMEM_BASE + 0x001A) +#define WSA883X_EMEM_27 (WSA883X_DIG_EMEM_BASE + 0x001B) +#define WSA883X_EMEM_28 (WSA883X_DIG_EMEM_BASE + 0x001C) +#define WSA883X_EMEM_29 (WSA883X_DIG_EMEM_BASE + 0x001D) +#define WSA883X_EMEM_30 (WSA883X_DIG_EMEM_BASE + 0x001E) +#define WSA883X_EMEM_31 (WSA883X_DIG_EMEM_BASE + 0x001F) +#define WSA883X_EMEM_32 (WSA883X_DIG_EMEM_BASE + 0x0020) +#define WSA883X_EMEM_33 (WSA883X_DIG_EMEM_BASE + 0x0021) +#define WSA883X_EMEM_34 (WSA883X_DIG_EMEM_BASE + 0x0022) +#define WSA883X_EMEM_35 (WSA883X_DIG_EMEM_BASE + 0x0023) +#define WSA883X_EMEM_36 (WSA883X_DIG_EMEM_BASE + 0x0024) +#define WSA883X_EMEM_37 (WSA883X_DIG_EMEM_BASE + 0x0025) +#define WSA883X_EMEM_38 (WSA883X_DIG_EMEM_BASE + 0x0026) +#define WSA883X_EMEM_39 (WSA883X_DIG_EMEM_BASE + 0x0027) +#define WSA883X_EMEM_40 (WSA883X_DIG_EMEM_BASE + 0x0028) +#define WSA883X_EMEM_41 (WSA883X_DIG_EMEM_BASE + 0x0029) +#define WSA883X_EMEM_42 (WSA883X_DIG_EMEM_BASE + 0x002A) +#define WSA883X_EMEM_43 (WSA883X_DIG_EMEM_BASE + 0x002B) +#define WSA883X_EMEM_44 (WSA883X_DIG_EMEM_BASE + 0x002C) +#define WSA883X_EMEM_45 (WSA883X_DIG_EMEM_BASE + 0x002D) +#define WSA883X_EMEM_46 (WSA883X_DIG_EMEM_BASE + 0x002E) +#define WSA883X_EMEM_47 (WSA883X_DIG_EMEM_BASE + 0x002F) +#define WSA883X_EMEM_48 (WSA883X_DIG_EMEM_BASE + 0x0030) +#define WSA883X_EMEM_49 (WSA883X_DIG_EMEM_BASE + 0x0031) +#define WSA883X_EMEM_50 (WSA883X_DIG_EMEM_BASE + 0x0032) +#define WSA883X_EMEM_51 (WSA883X_DIG_EMEM_BASE + 0x0033) +#define WSA883X_EMEM_52 (WSA883X_DIG_EMEM_BASE + 0x0034) +#define WSA883X_EMEM_53 (WSA883X_DIG_EMEM_BASE + 0x0035) +#define WSA883X_EMEM_54 (WSA883X_DIG_EMEM_BASE + 0x0036) +#define WSA883X_EMEM_55 (WSA883X_DIG_EMEM_BASE + 0x0037) +#define WSA883X_EMEM_56 (WSA883X_DIG_EMEM_BASE + 0x0038) +#define WSA883X_EMEM_57 (WSA883X_DIG_EMEM_BASE + 0x0039) +#define WSA883X_EMEM_58 (WSA883X_DIG_EMEM_BASE + 0x003A) +#define WSA883X_EMEM_59 (WSA883X_DIG_EMEM_BASE + 0x003B) +#define WSA883X_EMEM_60 (WSA883X_DIG_EMEM_BASE + 0x003C) +#define WSA883X_EMEM_61 (WSA883X_DIG_EMEM_BASE + 0x003D) +#define WSA883X_EMEM_62 (WSA883X_DIG_EMEM_BASE + 0x003E) +#define WSA883X_EMEM_63 (WSA883X_DIG_EMEM_BASE + 0x003F) + +#define WSA883X_NUM_REGISTERS (WSA883X_EMEM_63 + 1) +#define WSA883X_MAX_REGISTER (WSA883X_NUM_REGISTERS - 1) + +#define WSA883X_VERSION_1_0 0 +#define WSA883X_VERSION_1_1 1 + +#define WSA883X_MAX_SWR_PORTS 4 +#define WSA883X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WSA883X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) + +#define WSA883X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct wsa883x_priv { + struct regmap *regmap; + struct device *dev; + struct regulator *vdd; + struct sdw_slave *slave; + struct sdw_stream_config sconfig; + struct sdw_stream_runtime *sruntime; + struct sdw_port_config port_config[WSA883X_MAX_SWR_PORTS]; + struct gpio_desc *sd_n; + bool port_prepared[WSA883X_MAX_SWR_PORTS]; + bool port_enable[WSA883X_MAX_SWR_PORTS]; + int version; + int variant; + int active_ports; + int dev_mode; + int comp_offset; +}; + +enum { + WSA8830 = 0, + WSA8835, + WSA8832, + WSA8835_V2 = 5, +}; + +enum { + COMP_OFFSET0, + COMP_OFFSET1, + COMP_OFFSET2, + COMP_OFFSET3, + COMP_OFFSET4, +}; + +enum wsa_port_ids { + WSA883X_PORT_DAC, + WSA883X_PORT_COMP, + WSA883X_PORT_BOOST, + WSA883X_PORT_VISENSE, +}; + +static const char * const wsa_dev_mode_text[] = { + "Speaker", "Receiver", "Ultrasound" +}; + +enum { + SPEAKER, + RECEIVER, + ULTRASOUND, +}; + +static const struct soc_enum wsa_dev_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_dev_mode_text), wsa_dev_mode_text); + +/* 4 ports */ +static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = { + { + /* DAC */ + .num = 1, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + .read_only_wordlength = true, + }, { + /* COMP */ + .num = 2, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + .read_only_wordlength = true, + }, { + /* BOOST */ + .num = 3, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + .read_only_wordlength = true, + }, { + /* VISENSE */ + .num = 4, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 1, + .simple_ch_prep_sm = true, + .read_only_wordlength = true, + } +}; + +static struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = { + { + .num = 1, + .ch_mask = 0x1, + }, { + .num = 2, + .ch_mask = 0xf, + }, { + .num = 3, + .ch_mask = 0x3, + }, { /* IV feedback */ + .num = 4, + .ch_mask = 0x3, + }, +}; + +static struct reg_default wsa883x_defaults[] = { + { WSA883X_REF_CTRL, 0xD5 }, + { WSA883X_TEST_CTL_0, 0x06 }, + { WSA883X_BIAS_0, 0xD2 }, + { WSA883X_OP_CTL, 0xE0 }, + { WSA883X_IREF_CTL, 0x57 }, + { WSA883X_ISENS_CTL, 0x47 }, + { WSA883X_CLK_CTL, 0x87 }, + { WSA883X_TEST_CTL_1, 0x00 }, + { WSA883X_BIAS_1, 0x51 }, + { WSA883X_ADC_CTL, 0x01 }, + { WSA883X_DOUT_MSB, 0x00 }, + { WSA883X_DOUT_LSB, 0x00 }, + { WSA883X_VBAT_SNS, 0x40 }, + { WSA883X_ITRIM_CODE, 0x9F }, + { WSA883X_EN, 0x20 }, + { WSA883X_OVERRIDE1, 0x00 }, + { WSA883X_OVERRIDE2, 0x08 }, + { WSA883X_VSENSE1, 0xD3 }, + { WSA883X_ISENSE1, 0xD4 }, + { WSA883X_ISENSE2, 0x20 }, + { WSA883X_ISENSE_CAL, 0x00 }, + { WSA883X_MISC, 0x08 }, + { WSA883X_ADC_0, 0x00 }, + { WSA883X_ADC_1, 0x00 }, + { WSA883X_ADC_2, 0x40 }, + { WSA883X_ADC_3, 0x80 }, + { WSA883X_ADC_4, 0x25 }, + { WSA883X_ADC_5, 0x25 }, + { WSA883X_ADC_6, 0x08 }, + { WSA883X_ADC_7, 0x81 }, + { WSA883X_STATUS, 0x00 }, + { WSA883X_DAC_CTRL_REG, 0x53 }, + { WSA883X_DAC_EN_DEBUG_REG, 0x00 }, + { WSA883X_DAC_OPAMP_BIAS1_REG, 0x48 }, + { WSA883X_DAC_OPAMP_BIAS2_REG, 0x48 }, + { WSA883X_DAC_VCM_CTRL_REG, 0x88 }, + { WSA883X_DAC_VOLTAGE_CTRL_REG, 0xA5 }, + { WSA883X_ATEST1_REG, 0x00 }, + { WSA883X_ATEST2_REG, 0x00 }, + { WSA883X_SPKR_TOP_BIAS_REG1, 0x6A }, + { WSA883X_SPKR_TOP_BIAS_REG2, 0x65 }, + { WSA883X_SPKR_TOP_BIAS_REG3, 0x55 }, + { WSA883X_SPKR_TOP_BIAS_REG4, 0xA9 }, + { WSA883X_SPKR_CLIP_DET_REG, 0x9C }, + { WSA883X_SPKR_DRV_LF_BLK_EN, 0x0F }, + { WSA883X_SPKR_DRV_LF_EN, 0x0A }, + { WSA883X_SPKR_DRV_LF_MASK_DCC_CTL, 0x00 }, + { WSA883X_SPKR_DRV_LF_MISC_CTL, 0x3A }, + { WSA883X_SPKR_DRV_LF_REG_GAIN, 0x00 }, + { WSA883X_SPKR_DRV_OS_CAL_CTL, 0x00 }, + { WSA883X_SPKR_DRV_OS_CAL_CTL1, 0x90 }, + { WSA883X_SPKR_PWM_CLK_CTL, 0x00 }, + { WSA883X_SPKR_PDRV_HS_CTL, 0x52 }, + { WSA883X_SPKR_PDRV_LS_CTL, 0x48 }, + { WSA883X_SPKR_PWRSTG_DBG, 0x08 }, + { WSA883X_SPKR_OCP_CTL, 0xE2 }, + { WSA883X_SPKR_BBM_CTL, 0x92 }, + { WSA883X_PA_STATUS0, 0x00 }, + { WSA883X_PA_STATUS1, 0x00 }, + { WSA883X_PA_STATUS2, 0x80 }, + { WSA883X_EN_CTRL, 0x44 }, + { WSA883X_CURRENT_LIMIT, 0xCC }, + { WSA883X_IBIAS1, 0x00 }, + { WSA883X_IBIAS2, 0x00 }, + { WSA883X_IBIAS3, 0x00 }, + { WSA883X_LDO_PROG, 0x02 }, + { WSA883X_STABILITY_CTRL1, 0x8E }, + { WSA883X_STABILITY_CTRL2, 0x10 }, + { WSA883X_PWRSTAGE_CTRL1, 0x06 }, + { WSA883X_PWRSTAGE_CTRL2, 0x00 }, + { WSA883X_BYPASS_1, 0x19 }, + { WSA883X_BYPASS_2, 0x13 }, + { WSA883X_ZX_CTRL_1, 0xF0 }, + { WSA883X_ZX_CTRL_2, 0x04 }, + { WSA883X_MISC1, 0x06 }, + { WSA883X_MISC2, 0xA0 }, + { WSA883X_GMAMP_SUP1, 0x82 }, + { WSA883X_PWRSTAGE_CTRL3, 0x39 }, + { WSA883X_PWRSTAGE_CTRL4, 0x5F }, + { WSA883X_TEST1, 0x00 }, + { WSA883X_SPARE1, 0x00 }, + { WSA883X_SPARE2, 0x00 }, + { WSA883X_PON_CTL_0, 0x10 }, + { WSA883X_PON_CLT_1, 0xE0 }, + { WSA883X_PON_CTL_2, 0x90 }, + { WSA883X_PON_CTL_3, 0x70 }, + { WSA883X_CKWD_CTL_0, 0x34 }, + { WSA883X_CKWD_CTL_1, 0x0F }, + { WSA883X_CKWD_CTL_2, 0x00 }, + { WSA883X_CKSK_CTL_0, 0x00 }, + { WSA883X_PADSW_CTL_0, 0x00 }, + { WSA883X_TEST_0, 0x00 }, + { WSA883X_TEST_1, 0x00 }, + { WSA883X_STATUS_0, 0x00 }, + { WSA883X_STATUS_1, 0x00 }, + { WSA883X_CHIP_ID0, 0x00 }, + { WSA883X_CHIP_ID1, 0x00 }, + { WSA883X_CHIP_ID2, 0x02 }, + { WSA883X_CHIP_ID3, 0x02 }, + { WSA883X_BUS_ID, 0x00 }, + { WSA883X_CDC_RST_CTL, 0x01 }, + { WSA883X_TOP_CLK_CFG, 0x00 }, + { WSA883X_CDC_PATH_MODE, 0x00 }, + { WSA883X_CDC_CLK_CTL, 0xFF }, + { WSA883X_SWR_RESET_EN, 0x00 }, + { WSA883X_RESET_CTL, 0x00 }, + { WSA883X_PA_FSM_CTL, 0x00 }, + { WSA883X_PA_FSM_TIMER0, 0x80 }, + { WSA883X_PA_FSM_TIMER1, 0x80 }, + { WSA883X_PA_FSM_STA, 0x00 }, + { WSA883X_PA_FSM_ERR_COND, 0x00 }, + { WSA883X_PA_FSM_MSK, 0x00 }, + { WSA883X_PA_FSM_BYP, 0x01 }, + { WSA883X_PA_FSM_DBG, 0x00 }, + { WSA883X_TADC_VALUE_CTL, 0x03 }, + { WSA883X_TEMP_DETECT_CTL, 0x01 }, + { WSA883X_TEMP_MSB, 0x00 }, + { WSA883X_TEMP_LSB, 0x00 }, + { WSA883X_TEMP_CONFIG0, 0x00 }, + { WSA883X_TEMP_CONFIG1, 0x00 }, + { WSA883X_VBAT_ADC_FLT_CTL, 0x00 }, + { WSA883X_VBAT_DIN_MSB, 0x00 }, + { WSA883X_VBAT_DIN_LSB, 0x00 }, + { WSA883X_VBAT_DOUT, 0x00 }, + { WSA883X_SDM_PDM9_LSB, 0x00 }, + { WSA883X_SDM_PDM9_MSB, 0x00 }, + { WSA883X_CDC_RX_CTL, 0xFE }, + { WSA883X_CDC_SPK_DSM_A1_0, 0x00 }, + { WSA883X_CDC_SPK_DSM_A1_1, 0x01 }, + { WSA883X_CDC_SPK_DSM_A2_0, 0x96 }, + { WSA883X_CDC_SPK_DSM_A2_1, 0x09 }, + { WSA883X_CDC_SPK_DSM_A3_0, 0xAB }, + { WSA883X_CDC_SPK_DSM_A3_1, 0x05 }, + { WSA883X_CDC_SPK_DSM_A4_0, 0x1C }, + { WSA883X_CDC_SPK_DSM_A4_1, 0x02 }, + { WSA883X_CDC_SPK_DSM_A5_0, 0x17 }, + { WSA883X_CDC_SPK_DSM_A5_1, 0x02 }, + { WSA883X_CDC_SPK_DSM_A6_0, 0xAA }, + { WSA883X_CDC_SPK_DSM_A7_0, 0xE3 }, + { WSA883X_CDC_SPK_DSM_C_0, 0x69 }, + { WSA883X_CDC_SPK_DSM_C_1, 0x54 }, + { WSA883X_CDC_SPK_DSM_C_2, 0x02 }, + { WSA883X_CDC_SPK_DSM_C_3, 0x15 }, + { WSA883X_CDC_SPK_DSM_R1, 0xA4 }, + { WSA883X_CDC_SPK_DSM_R2, 0xB5 }, + { WSA883X_CDC_SPK_DSM_R3, 0x86 }, + { WSA883X_CDC_SPK_DSM_R4, 0x85 }, + { WSA883X_CDC_SPK_DSM_R5, 0xAA }, + { WSA883X_CDC_SPK_DSM_R6, 0xE2 }, + { WSA883X_CDC_SPK_DSM_R7, 0x62 }, + { WSA883X_CDC_SPK_GAIN_PDM_0, 0x00 }, + { WSA883X_CDC_SPK_GAIN_PDM_1, 0xFC }, + { WSA883X_CDC_SPK_GAIN_PDM_2, 0x05 }, + { WSA883X_PDM_WD_CTL, 0x00 }, + { WSA883X_DEM_BYPASS_DATA0, 0x00 }, + { WSA883X_DEM_BYPASS_DATA1, 0x00 }, + { WSA883X_DEM_BYPASS_DATA2, 0x00 }, + { WSA883X_DEM_BYPASS_DATA3, 0x00 }, + { WSA883X_WAVG_CTL, 0x06 }, + { WSA883X_WAVG_LRA_PER_0, 0xD1 }, + { WSA883X_WAVG_LRA_PER_1, 0x00 }, + { WSA883X_WAVG_DELTA_THETA_0, 0xE6 }, + { WSA883X_WAVG_DELTA_THETA_1, 0x04 }, + { WSA883X_WAVG_DIRECT_AMP_0, 0x50 }, + { WSA883X_WAVG_DIRECT_AMP_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP0_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP0_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP1_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP1_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP2_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP2_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP3_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP3_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP4_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP4_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP5_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP5_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP6_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP6_1, 0x00 }, + { WSA883X_WAVG_PTRN_AMP7_0, 0x50 }, + { WSA883X_WAVG_PTRN_AMP7_1, 0x00 }, + { WSA883X_WAVG_PER_0_1, 0x88 }, + { WSA883X_WAVG_PER_2_3, 0x88 }, + { WSA883X_WAVG_PER_4_5, 0x88 }, + { WSA883X_WAVG_PER_6_7, 0x88 }, + { WSA883X_WAVG_STA, 0x00 }, + { WSA883X_DRE_CTL_0, 0x70 }, + { WSA883X_DRE_CTL_1, 0x08 }, + { WSA883X_DRE_IDLE_DET_CTL, 0x1F }, + { WSA883X_CLSH_CTL_0, 0x37 }, + { WSA883X_CLSH_CTL_1, 0x81 }, + { WSA883X_CLSH_V_HD_PA, 0x0F }, + { WSA883X_CLSH_V_PA_MIN, 0x00 }, + { WSA883X_CLSH_OVRD_VAL, 0x00 }, + { WSA883X_CLSH_HARD_MAX, 0xFF }, + { WSA883X_CLSH_SOFT_MAX, 0xF5 }, + { WSA883X_CLSH_SIG_DP, 0x00 }, + { WSA883X_TAGC_CTL, 0x10 }, + { WSA883X_TAGC_TIME, 0x20 }, + { WSA883X_TAGC_E2E_GAIN, 0x02 }, + { WSA883X_TAGC_FORCE_VAL, 0x00 }, + { WSA883X_VAGC_CTL, 0x00 }, + { WSA883X_VAGC_TIME, 0x08 }, + { WSA883X_VAGC_ATTN_LVL_1_2, 0x21 }, + { WSA883X_VAGC_ATTN_LVL_3, 0x03 }, + { WSA883X_INTR_MODE, 0x00 }, + { WSA883X_INTR_MASK0, 0x90 }, + { WSA883X_INTR_MASK1, 0x00 }, + { WSA883X_INTR_STATUS0, 0x00 }, + { WSA883X_INTR_STATUS1, 0x00 }, + { WSA883X_INTR_CLEAR0, 0x00 }, + { WSA883X_INTR_CLEAR1, 0x00 }, + { WSA883X_INTR_LEVEL0, 0x00 }, + { WSA883X_INTR_LEVEL1, 0x00 }, + { WSA883X_INTR_SET0, 0x00 }, + { WSA883X_INTR_SET1, 0x00 }, + { WSA883X_INTR_TEST0, 0x00 }, + { WSA883X_INTR_TEST1, 0x00 }, + { WSA883X_OTP_CTRL0, 0x00 }, + { WSA883X_OTP_CTRL1, 0x00 }, + { WSA883X_HDRIVE_CTL_GROUP1, 0x00 }, + { WSA883X_PIN_CTL, 0x04 }, + { WSA883X_PIN_CTL_OE, 0x00 }, + { WSA883X_PIN_WDATA_IOPAD, 0x00 }, + { WSA883X_PIN_STATUS, 0x00 }, + { WSA883X_I2C_SLAVE_CTL, 0x00 }, + { WSA883X_PDM_TEST_MODE, 0x00 }, + { WSA883X_ATE_TEST_MODE, 0x00 }, + { WSA883X_DIG_DEBUG_MODE, 0x00 }, + { WSA883X_DIG_DEBUG_SEL, 0x00 }, + { WSA883X_DIG_DEBUG_EN, 0x00 }, + { WSA883X_SWR_HM_TEST0, 0x08 }, + { WSA883X_SWR_HM_TEST1, 0x00 }, + { WSA883X_SWR_PAD_CTL, 0x37 }, + { WSA883X_TADC_DETECT_DBG_CTL, 0x00 }, + { WSA883X_TADC_DEBUG_MSB, 0x00 }, + { WSA883X_TADC_DEBUG_LSB, 0x00 }, + { WSA883X_SAMPLE_EDGE_SEL, 0x7F }, + { WSA883X_SWR_EDGE_SEL, 0x00 }, + { WSA883X_TEST_MODE_CTL, 0x04 }, + { WSA883X_IOPAD_CTL, 0x00 }, + { WSA883X_ANA_CSR_DBG_ADD, 0x00 }, + { WSA883X_ANA_CSR_DBG_CTL, 0x12 }, + { WSA883X_SPARE_R, 0x00 }, + { WSA883X_SPARE_0, 0x00 }, + { WSA883X_SPARE_1, 0x00 }, + { WSA883X_SPARE_2, 0x00 }, + { WSA883X_SCODE, 0x00 }, + { WSA883X_OTP_REG_0, 0x05 }, + { WSA883X_OTP_REG_1, 0xFF }, + { WSA883X_OTP_REG_2, 0xC0 }, + { WSA883X_OTP_REG_3, 0xFF }, + { WSA883X_OTP_REG_4, 0xC0 }, + { WSA883X_OTP_REG_5, 0xFF }, + { WSA883X_OTP_REG_6, 0xFF }, + { WSA883X_OTP_REG_7, 0xFF }, + { WSA883X_OTP_REG_8, 0xFF }, + { WSA883X_OTP_REG_9, 0xFF }, + { WSA883X_OTP_REG_10, 0xFF }, + { WSA883X_OTP_REG_11, 0xFF }, + { WSA883X_OTP_REG_12, 0xFF }, + { WSA883X_OTP_REG_13, 0xFF }, + { WSA883X_OTP_REG_14, 0xFF }, + { WSA883X_OTP_REG_15, 0xFF }, + { WSA883X_OTP_REG_16, 0xFF }, + { WSA883X_OTP_REG_17, 0xFF }, + { WSA883X_OTP_REG_18, 0xFF }, + { WSA883X_OTP_REG_19, 0xFF }, + { WSA883X_OTP_REG_20, 0xFF }, + { WSA883X_OTP_REG_21, 0xFF }, + { WSA883X_OTP_REG_22, 0xFF }, + { WSA883X_OTP_REG_23, 0xFF }, + { WSA883X_OTP_REG_24, 0x37 }, + { WSA883X_OTP_REG_25, 0x3F }, + { WSA883X_OTP_REG_26, 0x03 }, + { WSA883X_OTP_REG_27, 0x00 }, + { WSA883X_OTP_REG_28, 0x00 }, + { WSA883X_OTP_REG_29, 0x00 }, + { WSA883X_OTP_REG_30, 0x00 }, + { WSA883X_OTP_REG_31, 0x03 }, + { WSA883X_OTP_REG_32, 0x00 }, + { WSA883X_OTP_REG_33, 0xFF }, + { WSA883X_OTP_REG_34, 0x00 }, + { WSA883X_OTP_REG_35, 0x00 }, + { WSA883X_OTP_REG_63, 0x40 }, + { WSA883X_EMEM_0, 0x00 }, + { WSA883X_EMEM_1, 0x00 }, + { WSA883X_EMEM_2, 0x00 }, + { WSA883X_EMEM_3, 0x00 }, + { WSA883X_EMEM_4, 0x00 }, + { WSA883X_EMEM_5, 0x00 }, + { WSA883X_EMEM_6, 0x00 }, + { WSA883X_EMEM_7, 0x00 }, + { WSA883X_EMEM_8, 0x00 }, + { WSA883X_EMEM_9, 0x00 }, + { WSA883X_EMEM_10, 0x00 }, + { WSA883X_EMEM_11, 0x00 }, + { WSA883X_EMEM_12, 0x00 }, + { WSA883X_EMEM_13, 0x00 }, + { WSA883X_EMEM_14, 0x00 }, + { WSA883X_EMEM_15, 0x00 }, + { WSA883X_EMEM_16, 0x00 }, + { WSA883X_EMEM_17, 0x00 }, + { WSA883X_EMEM_18, 0x00 }, + { WSA883X_EMEM_19, 0x00 }, + { WSA883X_EMEM_20, 0x00 }, + { WSA883X_EMEM_21, 0x00 }, + { WSA883X_EMEM_22, 0x00 }, + { WSA883X_EMEM_23, 0x00 }, + { WSA883X_EMEM_24, 0x00 }, + { WSA883X_EMEM_25, 0x00 }, + { WSA883X_EMEM_26, 0x00 }, + { WSA883X_EMEM_27, 0x00 }, + { WSA883X_EMEM_28, 0x00 }, + { WSA883X_EMEM_29, 0x00 }, + { WSA883X_EMEM_30, 0x00 }, + { WSA883X_EMEM_31, 0x00 }, + { WSA883X_EMEM_32, 0x00 }, + { WSA883X_EMEM_33, 0x00 }, + { WSA883X_EMEM_34, 0x00 }, + { WSA883X_EMEM_35, 0x00 }, + { WSA883X_EMEM_36, 0x00 }, + { WSA883X_EMEM_37, 0x00 }, + { WSA883X_EMEM_38, 0x00 }, + { WSA883X_EMEM_39, 0x00 }, + { WSA883X_EMEM_40, 0x00 }, + { WSA883X_EMEM_41, 0x00 }, + { WSA883X_EMEM_42, 0x00 }, + { WSA883X_EMEM_43, 0x00 }, + { WSA883X_EMEM_44, 0x00 }, + { WSA883X_EMEM_45, 0x00 }, + { WSA883X_EMEM_46, 0x00 }, + { WSA883X_EMEM_47, 0x00 }, + { WSA883X_EMEM_48, 0x00 }, + { WSA883X_EMEM_49, 0x00 }, + { WSA883X_EMEM_50, 0x00 }, + { WSA883X_EMEM_51, 0x00 }, + { WSA883X_EMEM_52, 0x00 }, + { WSA883X_EMEM_53, 0x00 }, + { WSA883X_EMEM_54, 0x00 }, + { WSA883X_EMEM_55, 0x00 }, + { WSA883X_EMEM_56, 0x00 }, + { WSA883X_EMEM_57, 0x00 }, + { WSA883X_EMEM_58, 0x00 }, + { WSA883X_EMEM_59, 0x00 }, + { WSA883X_EMEM_60, 0x00 }, + { WSA883X_EMEM_61, 0x00 }, + { WSA883X_EMEM_62, 0x00 }, + { WSA883X_EMEM_63, 0x00 }, +}; + +static bool wsa883x_readonly_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WSA883X_DOUT_MSB: + case WSA883X_DOUT_LSB: + case WSA883X_STATUS: + case WSA883X_PA_STATUS0: + case WSA883X_PA_STATUS1: + case WSA883X_PA_STATUS2: + case WSA883X_STATUS_0: + case WSA883X_STATUS_1: + case WSA883X_CHIP_ID0: + case WSA883X_CHIP_ID1: + case WSA883X_CHIP_ID2: + case WSA883X_CHIP_ID3: + case WSA883X_BUS_ID: + case WSA883X_PA_FSM_STA: + case WSA883X_PA_FSM_ERR_COND: + case WSA883X_TEMP_MSB: + case WSA883X_TEMP_LSB: + case WSA883X_VBAT_DIN_MSB: + case WSA883X_VBAT_DIN_LSB: + case WSA883X_VBAT_DOUT: + case WSA883X_SDM_PDM9_LSB: + case WSA883X_SDM_PDM9_MSB: + case WSA883X_WAVG_STA: + case WSA883X_INTR_STATUS0: + case WSA883X_INTR_STATUS1: + case WSA883X_OTP_CTRL1: + case WSA883X_PIN_STATUS: + case WSA883X_ATE_TEST_MODE: + case WSA883X_SWR_HM_TEST1: + case WSA883X_SPARE_R: + case WSA883X_OTP_REG_0: + return true; + } + return false; +} + +static bool wsa883x_writeable_register(struct device *dev, unsigned int reg) +{ + return !wsa883x_readonly_register(dev, reg); +} + +static bool wsa883x_volatile_register(struct device *dev, unsigned int reg) +{ + return wsa883x_readonly_register(dev, reg); +} + +static struct regmap_config wsa883x_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wsa883x_defaults, + .max_register = WSA883X_MAX_REGISTER, + .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults), + .volatile_reg = wsa883x_volatile_register, + .writeable_reg = wsa883x_writeable_register, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, + .use_single_read = true, +}; + +static const struct reg_sequence reg_init[] = { + {WSA883X_PA_FSM_BYP, 0x00}, + {WSA883X_ADC_6, 0x02}, + {WSA883X_CDC_SPK_DSM_A2_0, 0x0A}, + {WSA883X_CDC_SPK_DSM_A2_1, 0x08}, + {WSA883X_CDC_SPK_DSM_A3_0, 0xF3}, + {WSA883X_CDC_SPK_DSM_A3_1, 0x07}, + {WSA883X_CDC_SPK_DSM_A4_0, 0x79}, + {WSA883X_CDC_SPK_DSM_A4_1, 0x02}, + {WSA883X_CDC_SPK_DSM_A5_0, 0x0B}, + {WSA883X_CDC_SPK_DSM_A5_1, 0x02}, + {WSA883X_CDC_SPK_DSM_A6_0, 0x8A}, + {WSA883X_CDC_SPK_DSM_A7_0, 0x9B}, + {WSA883X_CDC_SPK_DSM_C_0, 0x68}, + {WSA883X_CDC_SPK_DSM_C_1, 0x54}, + {WSA883X_CDC_SPK_DSM_C_2, 0xF2}, + {WSA883X_CDC_SPK_DSM_C_3, 0x20}, + {WSA883X_CDC_SPK_DSM_R1, 0x83}, + {WSA883X_CDC_SPK_DSM_R2, 0x7F}, + {WSA883X_CDC_SPK_DSM_R3, 0x9D}, + {WSA883X_CDC_SPK_DSM_R4, 0x82}, + {WSA883X_CDC_SPK_DSM_R5, 0x8B}, + {WSA883X_CDC_SPK_DSM_R6, 0x9B}, + {WSA883X_CDC_SPK_DSM_R7, 0x3F}, + {WSA883X_VBAT_SNS, 0x20}, + {WSA883X_DRE_CTL_0, 0x92}, + {WSA883X_DRE_IDLE_DET_CTL, 0x0F}, + {WSA883X_CURRENT_LIMIT, 0xC4}, + {WSA883X_VAGC_TIME, 0x0F}, + {WSA883X_VAGC_ATTN_LVL_1_2, 0x00}, + {WSA883X_VAGC_ATTN_LVL_3, 0x01}, + {WSA883X_VAGC_CTL, 0x01}, + {WSA883X_TAGC_CTL, 0x1A}, + {WSA883X_TAGC_TIME, 0x2C}, + {WSA883X_TEMP_CONFIG0, 0x02}, + {WSA883X_TEMP_CONFIG1, 0x02}, + {WSA883X_OTP_REG_1, 0x49}, + {WSA883X_OTP_REG_2, 0x80}, + {WSA883X_OTP_REG_3, 0xC9}, + {WSA883X_OTP_REG_4, 0x40}, + {WSA883X_TAGC_CTL, 0x1B}, + {WSA883X_ADC_2, 0x00}, + {WSA883X_ADC_7, 0x85}, + {WSA883X_ADC_7, 0x87}, + {WSA883X_CKWD_CTL_0, 0x14}, + {WSA883X_CKWD_CTL_1, 0x1B}, + {WSA883X_GMAMP_SUP1, 0xE2}, +}; + +static void wsa883x_init(struct wsa883x_priv *wsa883x) +{ + struct regmap *regmap = wsa883x->regmap; + int variant, version; + + regmap_read(regmap, WSA883X_OTP_REG_0, &variant); + wsa883x->variant = variant & WSA883X_ID_MASK; + + regmap_read(regmap, WSA883X_CHIP_ID0, &version); + wsa883x->version = version; + + switch (wsa883x->variant) { + case WSA8830: + dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n", + wsa883x->version); + break; + case WSA8835: + dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n", + wsa883x->version); + break; + case WSA8832: + dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n", + wsa883x->version); + break; + case WSA8835_V2: + dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n", + wsa883x->version); + break; + default: + break; + } + + wsa883x->comp_offset = COMP_OFFSET2; + + /* Initial settings */ + regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init)); + + if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) { + wsa883x->comp_offset = COMP_OFFSET3; + regmap_update_bits(regmap, WSA883X_DRE_CTL_0, + WSA883X_DRE_OFFSET_MASK, + wsa883x->comp_offset); + } +} + +static int wsa883x_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) + wsa883x_init(wsa883x); + + return 0; +} + +static int wsa883x_port_prep(struct sdw_slave *slave, + struct sdw_prepare_ch *prepare_ch, + enum sdw_port_prep_ops state) +{ + struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + + if (state == SDW_OPS_PORT_POST_PREP) + wsa883x->port_prepared[prepare_ch->num - 1] = true; + else + wsa883x->port_prepared[prepare_ch->num - 1] = false; + + return 0; +} + +static struct sdw_slave_ops wsa883x_slave_ops = { + .update_status = wsa883x_update_status, + .port_prep = wsa883x_port_prep, +}; + +static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = wsa883x->dev_mode; + + return 0; +} + +static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (wsa883x->dev_mode == ucontrol->value.enumerated.item[0]) + return 0; + + wsa883x->dev_mode = ucontrol->value.enumerated.item[0]; + + return 1; +} + +static const DECLARE_TLV_DB_SCALE(pa_gain, -300, 150, -300); + +static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + + ucontrol->value.integer.value[0] = data->port_enable[portidx]; + + return 0; +} + +static int wsa883x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + + if (ucontrol->value.integer.value[0]) { + if (data->port_enable[portidx]) + return 0; + + data->port_enable[portidx] = true; + } else { + if (!data->port_enable[portidx]) + return 0; + + data->port_enable[portidx] = false; + } + + return 1; +} + +static int wsa883x_get_comp_offset(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wsa883x->comp_offset; + + return 0; +} + +static int wsa883x_set_comp_offset(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (wsa883x->comp_offset == ucontrol->value.integer.value[0]) + return 0; + + wsa883x->comp_offset = ucontrol->value.integer.value[0]; + + return 1; +} + +static int wsa883x_codec_probe(struct snd_soc_component *comp) +{ + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(comp); + + snd_soc_component_init_regmap(comp, wsa883x->regmap); + + return 0; +} + +static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (wsa883x->dev_mode) { + case RECEIVER: + snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE, + WSA883X_RXD_MODE_MASK, + WSA883X_RXD_MODE_HIFI); + snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL, + WSA883X_SPKR_PWM_FREQ_SEL_MASK, + WSA883X_SPKR_PWM_FREQ_F600KHZ); + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_PROG_DELAY_MASK, 0x0); + break; + case SPEAKER: + snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE, + WSA883X_RXD_MODE_MASK, + WSA883X_RXD_MODE_NORMAL); + snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL, + WSA883X_SPKR_PWM_FREQ_SEL_MASK, + WSA883X_SPKR_PWM_FREQ_F300KHZ); + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_PROG_DELAY_MASK, 0x9); + break; + default: + break; + } + + snd_soc_component_write_field(component, WSA883X_DRE_CTL_1, + WSA883X_DRE_GAIN_EN_MASK, + WSA883X_DRE_GAIN_FROM_CSR); + if (wsa883x->port_enable[WSA883X_PORT_COMP]) + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_OFFSET_MASK, + wsa883x->comp_offset); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_COEF_SEL_MASK, + WSA883X_VBAT_ADC_COEF_F_1DIV16); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_FLT_EN_MASK, 0x1); + snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, + WSA883X_PDM_EN_MASK, + WSA883X_PDM_ENABLE); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, + WSA883X_GLOBAL_PA_ENABLE); + + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_FLT_EN_MASK, 0x0); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_COEF_SEL_MASK, + WSA883X_VBAT_ADC_COEF_F_1DIV2); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, 0); + snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, + WSA883X_PDM_EN_MASK, 0); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget wsa883x_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + SND_SOC_DAPM_SPK("SPKR", wsa883x_spkr_event), +}; + +static const struct snd_kcontrol_new wsa883x_snd_controls[] = { + SOC_SINGLE_RANGE_TLV("PA Volume", WSA883X_DRE_CTL_1, 1, + 0x0, 0x1f, 1, pa_gain), + SOC_ENUM_EXT("WSA MODE", wsa_dev_mode_enum, + wsa_dev_mode_get, wsa_dev_mode_put), + SOC_SINGLE_EXT("COMP Offset", SND_SOC_NOPM, 0, 4, 0, + wsa883x_get_comp_offset, wsa883x_set_comp_offset), + SOC_SINGLE_EXT("DAC Switch", WSA883X_PORT_DAC, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("COMP Switch", WSA883X_PORT_COMP, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("BOOST Switch", WSA883X_PORT_BOOST, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("VISENSE Switch", WSA883X_PORT_VISENSE, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), +}; + +static const struct snd_soc_dapm_route wsa883x_audio_map[] = { + {"SPKR", NULL, "IN"}, +}; + +static const struct snd_soc_component_driver wsa883x_component_drv = { + .name = "WSA883x", + .probe = wsa883x_codec_probe, + .controls = wsa883x_snd_controls, + .num_controls = ARRAY_SIZE(wsa883x_snd_controls), + .dapm_widgets = wsa883x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets), + .dapm_routes = wsa883x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map), +}; + +static int wsa883x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev); + int i; + + wsa883x->active_ports = 0; + for (i = 0; i < WSA883X_MAX_SWR_PORTS; i++) { + if (!wsa883x->port_enable[i]) + continue; + + wsa883x->port_config[wsa883x->active_ports] = wsa883x_pconfig[i]; + wsa883x->active_ports++; + } + + wsa883x->sconfig.frame_rate = params_rate(params); + + return sdw_stream_add_slave(wsa883x->slave, &wsa883x->sconfig, + wsa883x->port_config, wsa883x->active_ports, + wsa883x->sruntime); +} + +static int wsa883x_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev); + + sdw_stream_remove_slave(wsa883x->slave, wsa883x->sruntime); + + return 0; +} + +static int wsa883x_set_sdw_stream(struct snd_soc_dai *dai, + void *stream, int direction) +{ + struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev); + + wsa883x->sruntime = stream; + + return 0; +} + +static int wsa883x_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + + if (mute) { + snd_soc_component_write_field(component, WSA883X_DRE_CTL_1, + WSA883X_DRE_GAIN_EN_MASK, 0); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, 0); + + } else { + snd_soc_component_write_field(component, WSA883X_DRE_CTL_1, + WSA883X_DRE_GAIN_EN_MASK, + WSA883X_DRE_GAIN_FROM_CSR); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, 1); + + } + + return 0; +} + +static const struct snd_soc_dai_ops wsa883x_dai_ops = { + .hw_params = wsa883x_hw_params, + .hw_free = wsa883x_hw_free, + .mute_stream = wsa883x_digital_mute, + .set_stream = wsa883x_set_sdw_stream, +}; + +static struct snd_soc_dai_driver wsa883x_dais[] = { + { + .name = "SPKR", + .playback = { + .stream_name = "SPKR Playback", + .rates = WSA883X_RATES | WSA883X_FRAC_RATES, + .formats = WSA883X_FORMATS, + .rate_max = 8000, + .rate_min = 352800, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &wsa883x_dai_ops, + }, +}; + +static int wsa883x_probe(struct sdw_slave *pdev, + const struct sdw_device_id *id) +{ + struct wsa883x_priv *wsa883x; + struct device *dev = &pdev->dev; + int ret; + + wsa883x = devm_kzalloc(&pdev->dev, sizeof(*wsa883x), GFP_KERNEL); + if (!wsa883x) + return -ENOMEM; + + wsa883x->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(wsa883x->vdd)) { + dev_err(dev, "No vdd regulator found\n"); + return PTR_ERR(wsa883x->vdd); + } + + ret = regulator_enable(wsa883x->vdd); + if (ret) { + dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret); + return ret; + } + + wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown", + GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(wsa883x->sd_n)) { + dev_err(&pdev->dev, "Shutdown Control GPIO not found\n"); + ret = PTR_ERR(wsa883x->sd_n); + goto err; + } + + dev_set_drvdata(&pdev->dev, wsa883x); + wsa883x->slave = pdev; + wsa883x->dev = &pdev->dev; + wsa883x->sconfig.ch_count = 1; + wsa883x->sconfig.bps = 1; + wsa883x->sconfig.direction = SDW_DATA_DIR_RX; + wsa883x->sconfig.type = SDW_STREAM_PDM; + + pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0); + pdev->prop.simple_clk_stop_capable = true; + pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; + pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + gpiod_direction_output(wsa883x->sd_n, 1); + + wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config); + if (IS_ERR(wsa883x->regmap)) { + dev_err(&pdev->dev, "regmap_init failed\n"); + ret = PTR_ERR(wsa883x->regmap); + goto err; + } + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &wsa883x_component_drv, + wsa883x_dais, + ARRAY_SIZE(wsa883x_dais)); +err: + if (ret) + regulator_disable(wsa883x->vdd); + + return ret; + +} + +static int __maybe_unused wsa883x_runtime_suspend(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + + return 0; +} + +static int __maybe_unused wsa883x_runtime_resume(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + regcache_cache_only(regmap, false); + regcache_sync(regmap); + + return 0; +} + +static const struct dev_pm_ops wsa883x_pm_ops = { + SET_RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL) +}; + +static const struct sdw_device_id wsa883x_swr_id[] = { + SDW_SLAVE_ENTRY(0x0217, 0x0202, 0), + {}, +}; + +MODULE_DEVICE_TABLE(sdw, wsa883x_swr_id); + +static struct sdw_driver wsa883x_codec_driver = { + .driver = { + .name = "wsa883x-codec", + .pm = &wsa883x_pm_ops, + .suppress_bind_attrs = true, + }, + .probe = wsa883x_probe, + .ops = &wsa883x_slave_ops, + .id_table = wsa883x_swr_id, +}; + +module_sdw_driver(wsa883x_codec_driver); + +MODULE_DESCRIPTION("WSA883x codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index d20ec1571010..c3d0a2a7c36f 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -385,7 +385,6 @@ static const struct snd_soc_component_driver zl38_component_dev = { .dapm_routes = zl38_dapm_routes, .num_dapm_routes = ARRAY_SIZE(zl38_dapm_routes), .endianness = 1, - .non_legacy_dai_naming = 1, }; static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) @@ -589,9 +588,7 @@ static int zl38_spi_probe(struct spi_device *spi) sizeof(template_chip), GFP_KERNEL); if (!priv->gpio_chip) return -ENOMEM; -#ifdef CONFIG_OF_GPIO - priv->gpio_chip->of_node = dev->of_node; -#endif + priv->gpio_chip->parent = dev; err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap); if (err) return err; |