aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig9
-rw-r--r--sound/soc/Makefile5
-rw-r--r--sound/soc/amd/Kconfig10
-rw-r--r--sound/soc/amd/Makefile2
-rw-r--r--sound/soc/amd/acp-config.c133
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c24
-rw-r--r--sound/soc/amd/acp-pcm-dma.c26
-rw-r--r--sound/soc/amd/acp-rt5645.c6
-rw-r--r--sound/soc/amd/acp.h1
-rw-r--r--sound/soc/amd/acp/Kconfig12
-rw-r--r--sound/soc/amd/acp/Makefile4
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c37
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c60
-rw-r--r--sound/soc/amd/acp/acp-pci.c161
-rw-r--r--sound/soc/amd/acp/acp-pdm.c193
-rw-r--r--sound/soc/amd/acp/acp-renoir.c189
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c15
-rw-r--r--sound/soc/amd/acp/amd.h23
-rw-r--r--sound/soc/amd/acp/chip_offset_byte.h26
-rw-r--r--sound/soc/amd/acp3x-rt5682-max9836.c10
-rw-r--r--sound/soc/amd/mach-config.h29
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c11
-rw-r--r--sound/soc/amd/raven/acp3x.h2
-rw-r--r--sound/soc/amd/renoir/acp3x-pdm-dma.c10
-rw-r--r--sound/soc/amd/renoir/rn-pci-acp3x.c7
-rw-r--r--sound/soc/amd/renoir/rn_acp3x.h3
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c26
-rw-r--r--sound/soc/amd/vangogh/acp5x-mach.c47
-rw-r--r--sound/soc/amd/vangogh/acp5x-pcm-dma.c78
-rw-r--r--sound/soc/amd/vangogh/acp5x.h31
-rw-r--r--sound/soc/amd/vangogh/pci-acp5x.c4
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c42
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c2
-rw-r--r--sound/soc/amd/yc/pci-acp6x.c9
-rw-r--r--sound/soc/atmel/Kconfig20
-rw-r--r--sound/soc/atmel/Makefile2
-rw-r--r--sound/soc/atmel/atmel-classd.c1
-rw-r--r--sound/soc/atmel/atmel-pdmic.c1
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c5
-rw-r--r--sound/soc/atmel/mchp-pdmc.c1084
-rw-r--r--sound/soc/atmel/mchp-spdifrx.c2
-rw-r--r--sound/soc/atmel/mikroe-proto.c26
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c78
-rw-r--r--sound/soc/atmel/sam9x5_wm8731.c13
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c32
-rw-r--r--sound/soc/au1x/Kconfig2
-rw-r--r--sound/soc/bcm/bcm63xx-i2s.h1
-rw-r--r--sound/soc/bcm/bcm63xx-pcm-whistler.c13
-rw-r--r--sound/soc/codecs/Kconfig142
-rw-r--r--sound/soc/codecs/Makefile34
-rw-r--r--sound/soc/codecs/ad193x-i2c.c6
-rw-r--r--sound/soc/codecs/adau1372-i2c.c4
-rw-r--r--sound/soc/codecs/adau1372.c1
-rw-r--r--sound/soc/codecs/adau1373.c5
-rw-r--r--sound/soc/codecs/adau1701.c99
-rw-r--r--sound/soc/codecs/adau1761-i2c.c8
-rw-r--r--sound/soc/codecs/adau1761-spi.c3
-rw-r--r--sound/soc/codecs/adau1761.c86
-rw-r--r--sound/soc/codecs/adau1781-i2c.c8
-rw-r--r--sound/soc/codecs/adau1781-spi.c3
-rw-r--r--sound/soc/codecs/adau17x1.c20
-rw-r--r--sound/soc/codecs/adau17x1.h1
-rw-r--r--sound/soc/codecs/adau1977-i2c.c8
-rw-r--r--sound/soc/codecs/adau7118-i2c.c5
-rw-r--r--sound/soc/codecs/adav803.c5
-rw-r--r--sound/soc/codecs/ak4118.c23
-rw-r--r--sound/soc/codecs/ak4375.c610
-rw-r--r--sound/soc/codecs/ak4535.c5
-rw-r--r--sound/soc/codecs/ak4613.c384
-rw-r--r--sound/soc/codecs/ak4641.c5
-rw-r--r--sound/soc/codecs/ak4642.c8
-rw-r--r--sound/soc/codecs/ak4671.c5
-rw-r--r--sound/soc/codecs/alc5623.c24
-rw-r--r--sound/soc/codecs/alc5632.c20
-rw-r--r--sound/soc/codecs/aw8738.c104
-rw-r--r--sound/soc/codecs/bt-sco.c8
-rw-r--r--sound/soc/codecs/cpcap.c2
-rw-r--r--sound/soc/codecs/cros_ec_codec.c7
-rw-r--r--sound/soc/codecs/cs35l32.c5
-rw-r--r--sound/soc/codecs/cs35l33.c5
-rw-r--r--sound/soc/codecs/cs35l34.c5
-rw-r--r--sound/soc/codecs/cs35l35.c7
-rw-r--r--sound/soc/codecs/cs35l36.c10
-rw-r--r--sound/soc/codecs/cs35l41-i2c.c28
-rw-r--r--sound/soc/codecs/cs35l41-lib.c1327
-rw-r--r--sound/soc/codecs/cs35l41-spi.c28
-rw-r--r--sound/soc/codecs/cs35l41-tables.c594
-rw-r--r--sound/soc/codecs/cs35l41.c948
-rw-r--r--sound/soc/codecs/cs35l41.h744
-rw-r--r--sound/soc/codecs/cs35l45-i2c.c74
-rw-r--r--sound/soc/codecs/cs35l45-spi.c74
-rw-r--r--sound/soc/codecs/cs35l45-tables.c202
-rw-r--r--sound/soc/codecs/cs35l45.c690
-rw-r--r--sound/soc/codecs/cs35l45.h217
-rw-r--r--sound/soc/codecs/cs4234.c5
-rw-r--r--sound/soc/codecs/cs4265.c23
-rw-r--r--sound/soc/codecs/cs4270.c20
-rw-r--r--sound/soc/codecs/cs4271-i2c.c5
-rw-r--r--sound/soc/codecs/cs42l42.c266
-rw-r--r--sound/soc/codecs/cs42l42.h816
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c9
-rw-r--r--sound/soc/codecs/cs42l51.c20
-rw-r--r--sound/soc/codecs/cs42l51.h2
-rw-r--r--sound/soc/codecs/cs42l52.c13
-rw-r--r--sound/soc/codecs/cs42l56.c11
-rw-r--r--sound/soc/codecs/cs42l73.c5
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c5
-rw-r--r--sound/soc/codecs/cs43130.c23
-rw-r--r--sound/soc/codecs/cs43130.h151
-rw-r--r--sound/soc/codecs/cs4341.c5
-rw-r--r--sound/soc/codecs/cs4349.c14
-rw-r--r--sound/soc/codecs/cs53l30.c21
-rw-r--r--sound/soc/codecs/cx2072x.c6
-rw-r--r--sound/soc/codecs/da7210.c5
-rw-r--r--sound/soc/codecs/da7213.c5
-rw-r--r--sound/soc/codecs/da7218.c19
-rw-r--r--sound/soc/codecs/da7219-aad.c18
-rw-r--r--sound/soc/codecs/da7219.c19
-rw-r--r--sound/soc/codecs/da732x.c5
-rw-r--r--sound/soc/codecs/da9055.c5
-rw-r--r--sound/soc/codecs/dmic.c5
-rw-r--r--sound/soc/codecs/es7134.c2
-rw-r--r--sound/soc/codecs/es7241.c58
-rw-r--r--sound/soc/codecs/es8316.c9
-rw-r--r--sound/soc/codecs/es8328-i2c.c5
-rw-r--r--sound/soc/codecs/es8328.c21
-rw-r--r--sound/soc/codecs/hdac_hda.c46
-rw-r--r--sound/soc/codecs/hdmi-codec.c17
-rw-r--r--sound/soc/codecs/inno_rk3036.c6
-rw-r--r--sound/soc/codecs/isabelle.c11
-rw-r--r--sound/soc/codecs/jz4770.c9
-rw-r--r--sound/soc/codecs/lm4857.c5
-rw-r--r--sound/soc/codecs/lm49453.c15
-rw-r--r--sound/soc/codecs/lochnagar-sc.c5
-rw-r--r--sound/soc/codecs/lpass-macro-common.c70
-rw-r--r--sound/soc/codecs/lpass-macro-common.h17
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c210
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c188
-rw-r--r--sound/soc/codecs/lpass-va-macro.c126
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c159
-rw-r--r--sound/soc/codecs/max9759.c31
-rw-r--r--sound/soc/codecs/max9768.c5
-rw-r--r--sound/soc/codecs/max98088.c45
-rw-r--r--sound/soc/codecs/max98090.c34
-rw-r--r--sound/soc/codecs/max98095.c55
-rw-r--r--sound/soc/codecs/max98371.c9
-rw-r--r--sound/soc/codecs/max98373-i2c.c5
-rw-r--r--sound/soc/codecs/max98373-sdw.c2
-rw-r--r--sound/soc/codecs/max98390.c27
-rw-r--r--sound/soc/codecs/max98390.h2
-rw-r--r--sound/soc/codecs/max98396.c1637
-rw-r--r--sound/soc/codecs/max98396.h305
-rw-r--r--sound/soc/codecs/max9850.c13
-rw-r--r--sound/soc/codecs/max98504.c6
-rw-r--r--sound/soc/codecs/max98520.c4
-rw-r--r--sound/soc/codecs/max9860.c18
-rw-r--r--sound/soc/codecs/max9867.c19
-rw-r--r--sound/soc/codecs/max9877.c5
-rw-r--r--sound/soc/codecs/max98925.c18
-rw-r--r--sound/soc/codecs/max98926.c9
-rw-r--r--sound/soc/codecs/max98927.c17
-rw-r--r--sound/soc/codecs/max98927.h2
-rw-r--r--sound/soc/codecs/mc13783.c15
-rw-r--r--sound/soc/codecs/ml26124.c12
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c29
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c14
-rw-r--r--sound/soc/codecs/mt6351.c10
-rw-r--r--sound/soc/codecs/mt6358.c14
-rw-r--r--sound/soc/codecs/mt6359.c10
-rw-r--r--sound/soc/codecs/mt6660.c11
-rw-r--r--sound/soc/codecs/nau8540.c5
-rw-r--r--sound/soc/codecs/nau8810.c5
-rw-r--r--sound/soc/codecs/nau8821.c6
-rw-r--r--sound/soc/codecs/nau8822.c9
-rw-r--r--sound/soc/codecs/nau8822.h3
-rw-r--r--sound/soc/codecs/nau8824.c5
-rw-r--r--sound/soc/codecs/nau8825.c5
-rw-r--r--sound/soc/codecs/pcm1681.c9
-rw-r--r--sound/soc/codecs/pcm1789-i2c.c9
-rw-r--r--sound/soc/codecs/pcm1789.c4
-rw-r--r--sound/soc/codecs/pcm1789.h2
-rw-r--r--sound/soc/codecs/pcm179x-i2c.c5
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c24
-rw-r--r--sound/soc/codecs/pcm186x.c26
-rw-r--r--sound/soc/codecs/pcm3060-i2c.c5
-rw-r--r--sound/soc/codecs/pcm3060.c15
-rw-r--r--sound/soc/codecs/pcm3060.h2
-rw-r--r--sound/soc/codecs/pcm3168a-i2c.c5
-rw-r--r--sound/soc/codecs/pcm3168a-spi.c4
-rw-r--r--sound/soc/codecs/pcm3168a.c194
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c5
-rw-r--r--sound/soc/codecs/pcm512x-spi.c3
-rw-r--r--sound/soc/codecs/pcm512x.c32
-rw-r--r--sound/soc/codecs/rk3328_codec.c2
-rw-r--r--sound/soc/codecs/rk817_codec.c8
-rw-r--r--sound/soc/codecs/rt1011.c5
-rw-r--r--sound/soc/codecs/rt1015.c5
-rw-r--r--sound/soc/codecs/rt1016.c5
-rw-r--r--sound/soc/codecs/rt1019.c8
-rw-r--r--sound/soc/codecs/rt1305.c5
-rw-r--r--sound/soc/codecs/rt1308-sdw.c76
-rw-r--r--sound/soc/codecs/rt1308-sdw.h1
-rw-r--r--sound/soc/codecs/rt1308.c5
-rw-r--r--sound/soc/codecs/rt1316-sdw.c3
-rw-r--r--sound/soc/codecs/rt274.c5
-rw-r--r--sound/soc/codecs/rt286.c5
-rw-r--r--sound/soc/codecs/rt298.c5
-rw-r--r--sound/soc/codecs/rt5514.c7
-rw-r--r--sound/soc/codecs/rt5616.c5
-rw-r--r--sound/soc/codecs/rt5631.c5
-rw-r--r--sound/soc/codecs/rt5640.c188
-rw-r--r--sound/soc/codecs/rt5640.h13
-rw-r--r--sound/soc/codecs/rt5645.c16
-rw-r--r--sound/soc/codecs/rt5651.c5
-rw-r--r--sound/soc/codecs/rt5659.c5
-rw-r--r--sound/soc/codecs/rt5660.c5
-rw-r--r--sound/soc/codecs/rt5663.c19
-rw-r--r--sound/soc/codecs/rt5665.c5
-rw-r--r--sound/soc/codecs/rt5668.c17
-rw-r--r--sound/soc/codecs/rt5670.c5
-rw-r--r--sound/soc/codecs/rt5682-i2c.c20
-rw-r--r--sound/soc/codecs/rt5682-sdw.c2
-rw-r--r--sound/soc/codecs/rt5682.c57
-rw-r--r--sound/soc/codecs/rt5682.h2
-rw-r--r--sound/soc/codecs/rt5682s.c160
-rw-r--r--sound/soc/codecs/rt5682s.h7
-rw-r--r--sound/soc/codecs/rt700.c3
-rw-r--r--sound/soc/codecs/rt711-sdca.c3
-rw-r--r--sound/soc/codecs/rt711.c10
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/rt715-sdca.c3
-rw-r--r--sound/soc/codecs/rt715.c3
-rw-r--r--sound/soc/codecs/rt9120.c115
-rw-r--r--sound/soc/codecs/sdw-mockup.c3
-rw-r--r--sound/soc/codecs/sgtl5000.c10
-rw-r--r--sound/soc/codecs/si476x.c2
-rw-r--r--sound/soc/codecs/simple-amplifier.c10
-rw-r--r--sound/soc/codecs/simple-mux.c10
-rw-r--r--sound/soc/codecs/ssm2305.c11
-rw-r--r--sound/soc/codecs/ssm2518.c5
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c8
-rw-r--r--sound/soc/codecs/ssm4567.c5
-rw-r--r--sound/soc/codecs/sta32x.c14
-rw-r--r--sound/soc/codecs/sta350.c14
-rw-r--r--sound/soc/codecs/sta350.h2
-rw-r--r--sound/soc/codecs/sta529.c5
-rw-r--r--sound/soc/codecs/sti-sas.c6
-rw-r--r--sound/soc/codecs/tas2552.c5
-rw-r--r--sound/soc/codecs/tas2562.c25
-rw-r--r--sound/soc/codecs/tas2764.c5
-rw-r--r--sound/soc/codecs/tas2770.c16
-rw-r--r--sound/soc/codecs/tas5086.c5
-rw-r--r--sound/soc/codecs/tas571x.c17
-rw-r--r--sound/soc/codecs/tas5720.c21
-rw-r--r--sound/soc/codecs/tas5805m.c567
-rw-r--r--sound/soc/codecs/tas6424.c17
-rw-r--r--sound/soc/codecs/tda7419.c5
-rw-r--r--sound/soc/codecs/tfa989x.c20
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c1462
-rw-r--r--sound/soc/codecs/tlv320adcx140.c16
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c5
-rw-r--r--sound/soc/codecs/tlv320aic26.h6
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c155
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h2
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c11
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c4
-rw-r--r--sound/soc/codecs/tlv320aic3x-i2c.c25
-rw-r--r--sound/soc/codecs/tlv320aic3x-spi.c4
-rw-r--r--sound/soc/codecs/tlv320dac33.c5
-rw-r--r--sound/soc/codecs/tpa6130a2.c21
-rw-r--r--sound/soc/codecs/ts3a227e.c5
-rw-r--r--sound/soc/codecs/tscs42xx.c11
-rw-r--r--sound/soc/codecs/tscs454.c45
-rw-r--r--sound/soc/codecs/twl4030.c12
-rw-r--r--sound/soc/codecs/uda1334.c2
-rw-r--r--sound/soc/codecs/uda134x.c6
-rw-r--r--sound/soc/codecs/uda1380.c15
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c102
-rw-r--r--sound/soc/codecs/wcd9335.c18
-rw-r--r--sound/soc/codecs/wcd934x.c45
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c1
-rw-r--r--sound/soc/codecs/wcd938x.c95
-rw-r--r--sound/soc/codecs/wl1273.c4
-rw-r--r--sound/soc/codecs/wm0010.c4
-rw-r--r--sound/soc/codecs/wm1250-ev1.c5
-rw-r--r--sound/soc/codecs/wm2000.c12
-rw-r--r--sound/soc/codecs/wm2200.c5
-rw-r--r--sound/soc/codecs/wm5100.c5
-rw-r--r--sound/soc/codecs/wm8350.c28
-rw-r--r--sound/soc/codecs/wm8510.c5
-rw-r--r--sound/soc/codecs/wm8523.c5
-rw-r--r--sound/soc/codecs/wm8580.c5
-rw-r--r--sound/soc/codecs/wm8711.c5
-rw-r--r--sound/soc/codecs/wm8728.c5
-rw-r--r--sound/soc/codecs/wm8731-i2c.c68
-rw-r--r--sound/soc/codecs/wm8731-spi.c59
-rw-r--r--sound/soc/codecs/wm8731.c272
-rw-r--r--sound/soc/codecs/wm8731.h27
-rw-r--r--sound/soc/codecs/wm8737.c5
-rw-r--r--sound/soc/codecs/wm8741.c5
-rw-r--r--sound/soc/codecs/wm8750.c5
-rw-r--r--sound/soc/codecs/wm8753.c5
-rw-r--r--sound/soc/codecs/wm8776.c5
-rw-r--r--sound/soc/codecs/wm8804-i2c.c5
-rw-r--r--sound/soc/codecs/wm8804-spi.c3
-rw-r--r--sound/soc/codecs/wm8900.c5
-rw-r--r--sound/soc/codecs/wm8903.c7
-rw-r--r--sound/soc/codecs/wm8904.c9
-rw-r--r--sound/soc/codecs/wm8940.c12
-rw-r--r--sound/soc/codecs/wm8955.c5
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c8
-rw-r--r--sound/soc/codecs/wm8960.c33
-rw-r--r--sound/soc/codecs/wm8961.c5
-rw-r--r--sound/soc/codecs/wm8962.c33
-rw-r--r--sound/soc/codecs/wm8971.c10
-rw-r--r--sound/soc/codecs/wm8974.c5
-rw-r--r--sound/soc/codecs/wm8978.c5
-rw-r--r--sound/soc/codecs/wm8983.c5
-rw-r--r--sound/soc/codecs/wm8985.c8
-rw-r--r--sound/soc/codecs/wm8988.c5
-rw-r--r--sound/soc/codecs/wm8990.c5
-rw-r--r--sound/soc/codecs/wm8991.c5
-rw-r--r--sound/soc/codecs/wm8993.c5
-rw-r--r--sound/soc/codecs/wm8995.c5
-rw-r--r--sound/soc/codecs/wm8996.c5
-rw-r--r--sound/soc/codecs/wm9081.c5
-rw-r--r--sound/soc/codecs/wm9090.c6
-rw-r--r--sound/soc/codecs/wm_adsp.c236
-rw-r--r--sound/soc/codecs/wm_adsp.h9
-rw-r--r--sound/soc/codecs/wsa881x.c56
-rw-r--r--sound/soc/codecs/zl38060.c4
-rw-r--r--sound/soc/dwc/dwc-i2s.c17
-rw-r--r--sound/soc/fsl/Kconfig1
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c32
-rw-r--r--sound/soc/fsl/fsl_asrc.c77
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c2
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c2
-rw-r--r--sound/soc/fsl/fsl_easrc.h2
-rw-r--r--sound/soc/fsl/fsl_esai.c8
-rw-r--r--sound/soc/fsl/fsl_micfil.c382
-rw-r--r--sound/soc/fsl/fsl_micfil.h269
-rw-r--r--sound/soc/fsl/fsl_mqs.c2
-rw-r--r--sound/soc/fsl/fsl_rpmsg.c2
-rw-r--r--sound/soc/fsl/fsl_sai.c153
-rw-r--r--sound/soc/fsl/fsl_sai.h15
-rw-r--r--sound/soc/fsl/fsl_spdif.c97
-rw-r--r--sound/soc/fsl/fsl_spdif.h14
-rw-r--r--sound/soc/fsl/fsl_ssi.c36
-rw-r--r--sound/soc/fsl/imx-card.c49
-rw-r--r--sound/soc/fsl/imx-es8328.c3
-rw-r--r--sound/soc/fsl/imx-hdmi.c11
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c2
-rw-r--r--sound/soc/fsl/imx-pcm.h9
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c18
-rw-r--r--sound/soc/fsl/imx-spdif.c4
-rw-r--r--sound/soc/fsl/imx-ssi.h2
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c11
-rw-r--r--sound/soc/generic/audio-graph-card.c5
-rw-r--r--sound/soc/generic/audio-graph-card2.c15
-rw-r--r--sound/soc/generic/simple-card-utils.c239
-rw-r--r--sound/soc/generic/simple-card.c29
-rw-r--r--sound/soc/generic/test-component.c5
-rw-r--r--sound/soc/img/img-i2s-in.c14
-rw-r--r--sound/soc/img/img-i2s-out.c24
-rw-r--r--sound/soc/img/img-parallel-out.c30
-rw-r--r--sound/soc/img/img-spdif-in.c14
-rw-r--r--sound/soc/img/img-spdif-out.c30
-rw-r--r--sound/soc/img/pistachio-internal-dac.c9
-rw-r--r--sound/soc/intel/Kconfig17
-rw-r--r--sound/soc/intel/Makefile1
-rw-r--r--sound/soc/intel/atom/sst-mfld-dsp.h4
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c14
-rw-r--r--sound/soc/intel/atom/sst/sst.c1
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c15
-rw-r--r--sound/soc/intel/avs/Makefile12
-rw-r--r--sound/soc/intel/avs/apl.c250
-rw-r--r--sound/soc/intel/avs/avs.h349
-rw-r--r--sound/soc/intel/avs/board_selection.c502
-rw-r--r--sound/soc/intel/avs/cldma.c316
-rw-r--r--sound/soc/intel/avs/cldma.h29
-rw-r--r--sound/soc/intel/avs/core.c692
-rw-r--r--sound/soc/intel/avs/dsp.c323
-rw-r--r--sound/soc/intel/avs/ipc.c623
-rw-r--r--sound/soc/intel/avs/loader.c692
-rw-r--r--sound/soc/intel/avs/messages.c726
-rw-r--r--sound/soc/intel/avs/messages.h803
-rw-r--r--sound/soc/intel/avs/path.c1005
-rw-r--r--sound/soc/intel/avs/path.h72
-rw-r--r--sound/soc/intel/avs/pcm.c1182
-rw-r--r--sound/soc/intel/avs/registers.h83
-rw-r--r--sound/soc/intel/avs/skl.c125
-rw-r--r--sound/soc/intel/avs/topology.c1598
-rw-r--r--sound/soc/intel/avs/topology.h194
-rw-r--r--sound/soc/intel/avs/trace.c33
-rw-r--r--sound/soc/intel/avs/trace.h154
-rw-r--r--sound/soc/intel/avs/utils.c324
-rw-r--r--sound/soc/intel/boards/Kconfig95
-rw-r--r--sound/soc/intel/boards/Makefile12
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c8
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c6
-rw-r--r--sound/soc/intel/boards/broadwell.c4
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c7
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c7
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c14
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c2
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c12
-rw-r--r--sound/soc/intel/boards/bytcht_nocodec.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c126
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c9
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c8
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c32
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c8
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c8
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c14
-rw-r--r--sound/soc/intel/boards/cml_rt1011_rt5682.c5
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c7
-rw-r--r--sound/soc/intel/boards/haswell.c2
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c5
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c5
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c15
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c7
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c7
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.c8
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c6
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c6
-rw-r--r--sound/soc/intel/boards/skl_rt286.c5
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.c195
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.h25
-rw-r--r--sound/soc/intel/boards/sof_cs42l42.c5
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c2
-rw-r--r--sound/soc/intel/boards/sof_es8336.c241
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.c180
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.h16
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c651
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.c265
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.h16
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c266
-rw-r--r--sound/soc/intel/boards/sof_sdw.c160
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h7
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt5682.c14
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt700.c14
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711.c14
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711_sdca.c14
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715.c7
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715_sdca.c7
-rw-r--r--sound/soc/intel/boards/sof_ssp_amp.c498
-rw-r--r--sound/soc/intel/catpt/dsp.c14
-rw-r--r--sound/soc/intel/catpt/messages.h4
-rw-r--r--sound/soc/intel/catpt/pcm.c43
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c108
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-bxt-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-byt-match.c13
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cht-match.c12
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c23
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cnl-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ehl-match.c1
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-glk-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hda-match.c2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c5
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c5
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c19
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c35
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c102
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c11
-rw-r--r--sound/soc/intel/skylake/skl-topology.c29
-rw-r--r--sound/soc/intel/skylake/skl-topology.h3
-rw-r--r--sound/soc/intel/skylake/skl.c5
-rw-r--r--sound/soc/intel/skylake/skl.h4
-rw-r--r--sound/soc/mediatek/Kconfig27
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c9
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c21
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c9
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c9
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c11
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c43
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c37
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c216
-rw-r--r--sound/soc/mediatek/mt8195/Makefile3
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-clk.c294
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-clk.h11
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-pcm.c32
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-pcm.c77
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c1108
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c (renamed from sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c)986
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-reg.h1
-rw-r--r--sound/soc/meson/aiu-acodec-ctrl.c5
-rw-r--r--sound/soc/meson/aiu-codec-ctrl.c5
-rw-r--r--sound/soc/meson/aiu-encoder-i2s.c33
-rw-r--r--sound/soc/meson/aiu-fifo-i2s.c19
-rw-r--r--sound/soc/meson/aiu-fifo.c6
-rw-r--r--sound/soc/meson/aiu.c39
-rw-r--r--sound/soc/meson/axg-card.c1
-rw-r--r--sound/soc/meson/axg-fifo.c16
-rw-r--r--sound/soc/meson/axg-pdm.c25
-rw-r--r--sound/soc/meson/axg-spdifin.c17
-rw-r--r--sound/soc/meson/axg-spdifout.c17
-rw-r--r--sound/soc/meson/axg-tdm-formatter.c50
-rw-r--r--sound/soc/meson/axg-tdm-interface.c51
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c2
-rw-r--r--sound/soc/meson/meson-card-utils.c8
-rw-r--r--sound/soc/meson/t9015.c14
-rw-r--r--sound/soc/mxs/mxs-saif.c6
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c11
-rw-r--r--sound/soc/pxa/Kconfig13
-rw-r--r--sound/soc/pxa/Makefile2
-rw-r--r--sound/soc/pxa/corgi.c43
-rw-r--r--sound/soc/pxa/e740_wm9705.c37
-rw-r--r--sound/soc/pxa/e750_wm9705.c33
-rw-r--r--sound/soc/pxa/e800_wm9712.c33
-rw-r--r--sound/soc/pxa/em-x270.c2
-rw-r--r--sound/soc/pxa/hx4700.c43
-rw-r--r--sound/soc/pxa/imote2.c99
-rw-r--r--sound/soc/pxa/magician.c141
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c2
-rw-r--r--sound/soc/pxa/palm27x.c9
-rw-r--r--sound/soc/pxa/poodle.c51
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c24
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c112
-rw-r--r--sound/soc/pxa/spitz.c58
-rw-r--r--sound/soc/pxa/tosa.c25
-rw-r--r--sound/soc/pxa/ttc-dkb.c14
-rw-r--r--sound/soc/pxa/z2.c15
-rw-r--r--sound/soc/qcom/Kconfig29
-rw-r--r--sound/soc/qcom/Makefile6
-rw-r--r--sound/soc/qcom/apq8016_sbc.c136
-rw-r--r--sound/soc/qcom/common.c20
-rw-r--r--sound/soc/qcom/lpass-cdc-dma.c301
-rw-r--r--sound/soc/qcom/lpass-cpu.c253
-rw-r--r--sound/soc/qcom/lpass-lpaif-reg.h127
-rw-r--r--sound/soc/qcom/lpass-platform.c643
-rw-r--r--sound/soc/qcom/lpass-sc7280.c438
-rw-r--r--sound/soc/qcom/lpass.h142
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-dai.c7
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c14
-rw-r--r--sound/soc/qcom/sc7180.c28
-rw-r--r--sound/soc/qcom/sc7280.c379
-rw-r--r--sound/soc/qcom/sdm845.c16
-rw-r--r--sound/soc/qcom/sm8250.c6
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c18
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c34
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c15
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c12
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c16
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c2
-rw-r--r--sound/soc/samsung/aries_wm8994.c21
-rw-r--r--sound/soc/samsung/arndale.c5
-rw-r--r--sound/soc/samsung/bells.c4
-rw-r--r--sound/soc/samsung/h1940_uda1380.c3
-rw-r--r--sound/soc/samsung/i2s.c4
-rw-r--r--sound/soc/samsung/idma.c7
-rw-r--r--sound/soc/samsung/littlemill.c11
-rw-r--r--sound/soc/samsung/lowland.c18
-rw-r--r--sound/soc/samsung/midas_wm1811.c3
-rw-r--r--sound/soc/samsung/odroid.c4
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c3
-rw-r--r--sound/soc/samsung/smartq_wm8987.c8
-rw-r--r--sound/soc/samsung/smdk_wm8994.c4
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c4
-rw-r--r--sound/soc/samsung/snow.c9
-rw-r--r--sound/soc/samsung/spdif.c3
-rw-r--r--sound/soc/samsung/speyside.c19
-rw-r--r--sound/soc/samsung/tm2_wm5110.c3
-rw-r--r--sound/soc/samsung/tobermory.c17
-rw-r--r--sound/soc/sh/Kconfig2
-rw-r--r--sound/soc/sh/fsi.c19
-rw-r--r--sound/soc/sh/rcar/core.c17
-rw-r--r--sound/soc/sh/rcar/dma.c9
-rw-r--r--sound/soc/sh/rcar/rsnd.h2
-rw-r--r--sound/soc/sh/rcar/src.c7
-rw-r--r--sound/soc/sh/rcar/ssi.c14
-rw-r--r--sound/soc/sh/rcar/ssiu.c11
-rw-r--r--sound/soc/sh/rz-ssi.c140
-rw-r--r--sound/soc/soc-acpi.c7
-rw-r--r--sound/soc/soc-card.c56
-rw-r--r--sound/soc/soc-component.c42
-rw-r--r--sound/soc/soc-compress.c5
-rw-r--r--sound/soc/soc-core.c157
-rw-r--r--sound/soc/soc-dai.c40
-rw-r--r--sound/soc/soc-dapm.c23
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c67
-rw-r--r--sound/soc/soc-jack.c2
-rw-r--r--sound/soc/soc-ops.c88
-rw-r--r--sound/soc/soc-pcm.c424
-rw-r--r--sound/soc/soc-topology.c556
-rw-r--r--sound/soc/soc-utils-test.c186
-rw-r--r--sound/soc/soc-utils.c45
-rw-r--r--sound/soc/sof/Kconfig49
-rw-r--r--sound/soc/sof/Makefile24
-rw-r--r--sound/soc/sof/amd/Kconfig33
-rw-r--r--sound/soc/sof/amd/Makefile11
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h79
-rw-r--r--sound/soc/sof/amd/acp-ipc.c193
-rw-r--r--sound/soc/sof/amd/acp-loader.c208
-rw-r--r--sound/soc/sof/amd/acp-pcm.c85
-rw-r--r--sound/soc/sof/amd/acp-stream.c184
-rw-r--r--sound/soc/sof/amd/acp-trace.c64
-rw-r--r--sound/soc/sof/amd/acp.c497
-rw-r--r--sound/soc/sof/amd/acp.h229
-rw-r--r--sound/soc/sof/amd/pci-rn.c174
-rw-r--r--sound/soc/sof/amd/renoir.c181
-rw-r--r--sound/soc/sof/compress.c272
-rw-r--r--sound/soc/sof/control.c608
-rw-r--r--sound/soc/sof/core.c232
-rw-r--r--sound/soc/sof/debug.c502
-rw-r--r--sound/soc/sof/imx/Kconfig46
-rw-r--r--sound/soc/sof/imx/imx-common.c28
-rw-r--r--sound/soc/sof/imx/imx-common.h11
-rw-r--r--sound/soc/sof/imx/imx-ops.h10
-rw-r--r--sound/soc/sof/imx/imx8.c248
-rw-r--r--sound/soc/sof/imx/imx8m.c275
-rw-r--r--sound/soc/sof/intel/Kconfig20
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/apl.c153
-rw-r--r--sound/soc/sof/intel/atom.c64
-rw-r--r--sound/soc/sof/intel/atom.h4
-rw-r--r--sound/soc/sof/intel/bdw.c94
-rw-r--r--sound/soc/sof/intel/byt.c69
-rw-r--r--sound/soc/sof/intel/cnl.c253
-rw-r--r--sound/soc/sof/intel/hda-codec.c3
-rw-r--r--sound/soc/sof/intel/hda-common-ops.c106
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c2
-rw-r--r--sound/soc/sof/intel/hda-dai.c605
-rw-r--r--sound/soc/sof/intel/hda-dsp.c106
-rw-r--r--sound/soc/sof/intel/hda-ipc.c138
-rw-r--r--sound/soc/sof/intel/hda-loader.c280
-rw-r--r--sound/soc/sof/intel/hda-pcm.c154
-rw-r--r--sound/soc/sof/intel/hda-probes.c104
-rw-r--r--sound/soc/sof/intel/hda-stream.c227
-rw-r--r--sound/soc/sof/intel/hda-trace.c23
-rw-r--r--sound/soc/sof/intel/hda.c451
-rw-r--r--sound/soc/sof/intel/hda.h156
-rw-r--r--sound/soc/sof/intel/icl.c191
-rw-r--r--sound/soc/sof/intel/pci-apl.c36
-rw-r--r--sound/soc/sof/intel/pci-cnl.c54
-rw-r--r--sound/soc/sof/intel/pci-icl.c36
-rw-r--r--sound/soc/sof/intel/pci-tgl.c103
-rw-r--r--sound/soc/sof/intel/pci-tng.c39
-rw-r--r--sound/soc/sof/intel/shim.h27
-rw-r--r--sound/soc/sof/intel/tgl.c198
-rw-r--r--sound/soc/sof/iomem-utils.c (renamed from sound/soc/sof/utils.c)61
-rw-r--r--sound/soc/sof/ipc.c937
-rw-r--r--sound/soc/sof/ipc3-control.c709
-rw-r--r--sound/soc/sof/ipc3-dtrace.c649
-rw-r--r--sound/soc/sof/ipc3-loader.c415
-rw-r--r--sound/soc/sof/ipc3-pcm.c370
-rw-r--r--sound/soc/sof/ipc3-priv.h65
-rw-r--r--sound/soc/sof/ipc3-topology.c2416
-rw-r--r--sound/soc/sof/ipc3.c1079
-rw-r--r--sound/soc/sof/ipc4-loader.c210
-rw-r--r--sound/soc/sof/ipc4-priv.h44
-rw-r--r--sound/soc/sof/ipc4.c606
-rw-r--r--sound/soc/sof/loader.c714
-rw-r--r--sound/soc/sof/mediatek/Kconfig44
-rw-r--r--sound/soc/sof/mediatek/Makefile4
-rw-r--r--sound/soc/sof/mediatek/adsp_helper.h53
-rw-r--r--sound/soc/sof/mediatek/mt8186/Makefile4
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186-clk.c101
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186-clk.h24
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186-loader.c58
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c554
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.h80
-rw-r--r--sound/soc/sof/mediatek/mt8195/Makefile3
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-clk.c158
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-clk.h28
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-loader.c56
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c637
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.h158
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.c84
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.h10
-rw-r--r--sound/soc/sof/ops.c47
-rw-r--r--sound/soc/sof/ops.h181
-rw-r--r--sound/soc/sof/pcm.c367
-rw-r--r--sound/soc/sof/pm.c125
-rw-r--r--sound/soc/sof/sof-acpi-dev.c6
-rw-r--r--sound/soc/sof/sof-audio.c839
-rw-r--r--sound/soc/sof/sof-audio.h326
-rw-r--r--sound/soc/sof/sof-client-ipc-flood-test.c395
-rw-r--r--sound/soc/sof/sof-client-ipc-msg-injector.c345
-rw-r--r--sound/soc/sof/sof-client-probes.c819
-rw-r--r--sound/soc/sof/sof-client-probes.h31
-rw-r--r--sound/soc/sof/sof-client.c523
-rw-r--r--sound/soc/sof/sof-client.h69
-rw-r--r--sound/soc/sof/sof-of-dev.c78
-rw-r--r--sound/soc/sof/sof-of-dev.h18
-rw-r--r--sound/soc/sof/sof-pci-dev.c143
-rw-r--r--sound/soc/sof/sof-priv.h415
-rw-r--r--sound/soc/sof/sof-probes.c364
-rw-r--r--sound/soc/sof/sof-probes.h38
-rw-r--r--sound/soc/sof/sof-utils.c77
-rw-r--r--sound/soc/sof/sof-utils.h19
-rw-r--r--sound/soc/sof/stream-ipc.c9
-rw-r--r--sound/soc/sof/topology.c2915
-rw-r--r--sound/soc/sof/trace.c571
-rw-r--r--sound/soc/sof/xtensa/core.c44
-rw-r--r--sound/soc/sti/uniperif_player.c6
-rw-r--r--sound/soc/sti/uniperif_reader.c2
-rw-r--r--sound/soc/stm/stm32_adfsdm.c5
-rw-r--r--sound/soc/stm/stm32_i2s.c66
-rw-r--r--sound/soc/stm/stm32_sai.c37
-rw-r--r--sound/soc/stm/stm32_sai_sub.c29
-rw-r--r--sound/soc/stm/stm32_spdifrx.c48
-rw-r--r--sound/soc/sunxi/sun4i-codec.c3
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c68
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c115
-rw-r--r--sound/soc/sunxi/sun8i-codec.c56
-rw-r--r--sound/soc/tegra/Kconfig12
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra186_asrc.c1046
-rw-r--r--sound/soc/tegra/tegra186_asrc.h112
-rw-r--r--sound/soc/tegra/tegra20_i2s.c49
-rw-r--r--sound/soc/tegra/tegra20_spdif.c197
-rw-r--r--sound/soc/tegra/tegra20_spdif.h1
-rw-r--r--sound/soc/tegra/tegra210_ahub.c228
-rw-r--r--sound/soc/tegra/tegra210_ahub.h4
-rw-r--r--sound/soc/tegra/tegra210_mvc.c209
-rw-r--r--sound/soc/tegra/tegra210_mvc.h5
-rw-r--r--sound/soc/tegra/tegra_asoc_machine.c39
-rw-r--r--sound/soc/tegra/tegra_asoc_machine.h1
-rw-r--r--sound/soc/tegra/tegra_pcm.c6
-rw-r--r--sound/soc/tegra/tegra_pcm.h1
-rw-r--r--sound/soc/tegra/tegra_wm8903.c10
-rw-r--r--sound/soc/ti/ams-delta.c4
-rw-r--r--sound/soc/ti/davinci-i2s.c5
-rw-r--r--sound/soc/ti/davinci-mcasp.c23
-rw-r--r--sound/soc/ti/j721e-evm.c54
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c8
-rw-r--r--sound/soc/ti/omap-dmic.c2
-rw-r--r--sound/soc/ti/omap-twl4030.c8
-rw-r--r--sound/soc/ti/osk5912.c4
-rw-r--r--sound/soc/ti/rx51.c2
-rw-r--r--sound/soc/uniphier/Kconfig2
-rw-r--r--sound/soc/uniphier/aio-compress.c7
-rw-r--r--sound/soc/ux500/mop500_ab8500.c9
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c52
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c147
-rw-r--r--sound/soc/xilinx/xlnx_spdif.c10
741 files changed, 53988 insertions, 18869 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5dcf77af07af..7d4747b6bab2 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -14,7 +14,7 @@ menuconfig SND_SOC
If you want ASoC support, you should say Y here and also to the
specific driver for your SoC platform below.
-
+
ASoC provides power efficient ALSA support for embedded battery powered
SoC based systems like PDA's, Phones and Personal Media Players.
@@ -55,6 +55,13 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST
userspace applications such as pulseaudio, to prevent unnecessary
problems.
+config SND_SOC_UTILS_KUNIT_TEST
+ tristate "KUnit tests for SoC utils"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ If you want to perform tests on ALSA SoC utils library say Y here.
+
config SND_SOC_ACPI
tristate
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index a7b37c06dc43..d4528962ac34 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,6 +12,11 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o
endif
+ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
+# snd-soc-test-objs := soc-utils-test.o
+obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) := soc-utils-test.o
+endif
+
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
endif
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 2c6af3f8f296..1381aec23048 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -44,6 +44,7 @@ config SND_SOC_AMD_RV_RT5682_MACH
config SND_SOC_AMD_RENOIR
tristate "AMD Audio Coprocessor - Renoir support"
+ select SND_AMD_ACP_CONFIG
depends on X86 && PCI
help
This option enables ACP support for Renoir platform
@@ -68,7 +69,7 @@ config SND_SOC_AMD_VANGOGH_MACH
tristate "AMD Vangogh support for NAU8821 CS35L41"
select SND_SOC_NAU8821
select SND_SOC_CS35L41_SPI
- depends on SND_SOC_AMD_ACP5x && I2C
+ depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER
help
This option enables machine driver for Vangogh platform
using NAU8821 and CS35L41 codecs.
@@ -96,4 +97,11 @@ config SND_SOC_AMD_YC_MACH
Say m if you have such a device.
If unsure select "N".
+config SND_AMD_ACP_CONFIG
+ tristate "AMD ACP configuration selection"
+ select SND_SOC_ACPI if ACPI
+ help
+ This option adds an auto detection to determine which ACP
+ driver modules to use
+
source "sound/soc/amd/acp/Kconfig"
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index f1d42bbda709..4b1f77930a4a 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -3,6 +3,7 @@ acp_audio_dma-objs := acp-pcm-dma.o
snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
+snd-acp-config-objs := acp-config.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
@@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
+obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
new file mode 100644
index 000000000000..5cbc82eca4c9
--- /dev/null
+++ b/sound/soc/amd/acp-config.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2021 Advanced Micro Devices, Inc.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+//
+
+/* ACP machine configuration module */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "../sof/amd/acp.h"
+#include "mach-config.h"
+
+static int acp_quirk_data;
+
+static const struct config_entry config_table[] = {
+ {
+ .flags = FLAG_AMD_SOF,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AMD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Majolica-CZN"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_SOF,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ },
+ },
+ {}
+ },
+ },
+};
+
+int snd_amd_acp_find_config(struct pci_dev *pci)
+{
+ const struct config_entry *table = config_table;
+ u16 device = pci->device;
+ int i;
+
+ /* Do not enable FLAGS on older platforms with Rev id zero */
+ if (!pci->revision)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) {
+ if (table->device != device)
+ continue;
+ if (table->dmi_table && !dmi_check_system(table->dmi_table))
+ continue;
+ acp_quirk_data = table->flags;
+ return table->flags;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_amd_acp_find_config);
+
+static struct snd_soc_acpi_codecs amp_rt1019 = {
+ .num_codecs = 1,
+ .codecs = {"10EC1019"}
+};
+
+static struct snd_soc_acpi_codecs amp_max = {
+ .num_codecs = 1,
+ .codecs = {"MX98360A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
+ {
+ .id = "10EC5682",
+ .drv_name = "rt5682-rt1019",
+ .pdata = (void *)&acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ .fw_filename = "sof-rn.ri",
+ .sof_tplg_filename = "sof-rn-rt5682-rt1019.tplg",
+ },
+ {
+ .id = "10EC5682",
+ .drv_name = "rt5682-max",
+ .pdata = (void *)&acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max,
+ .fw_filename = "sof-rn.ri",
+ .sof_tplg_filename = "sof-rn-rt5682-max98360.tplg",
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "rt5682s-max",
+ .pdata = (void *)&acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max,
+ .fw_filename = "sof-rn.ri",
+ .sof_tplg_filename = "sof-rn-rt5682-max98360.tplg",
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "rt5682s-rt1019",
+ .pdata = (void *)&acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ .fw_filename = "sof-rn.ri",
+ .sof_tplg_filename = "sof-rn-rt5682-rt1019.tplg",
+ },
+ {
+ .id = "AMDI1019",
+ .drv_name = "renoir-dsp",
+ .pdata = (void *)&acp_quirk_data,
+ .fw_filename = "sof-rn.ri",
+ .sof_tplg_filename = "sof-acp.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index b2065f3fe42c..ef1b4cefc273 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -71,7 +71,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack, NULL, 0);
+ &cz_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -151,7 +151,7 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack, NULL, 0);
+ &cz_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -522,7 +522,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "amd-da7219-play",
.stream_name = "Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.init = cz_da7219_init,
.dpcm_playback = 1,
.stop_dma_first = 1,
@@ -533,7 +533,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "amd-da7219-cap",
.stream_name = "Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_da7219_cap_ops,
@@ -543,7 +543,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "amd-max98357-play",
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_playback = 1,
.stop_dma_first = 1,
.ops = &cz_max_play_ops,
@@ -554,7 +554,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "dmic0",
.stream_name = "DMIC0 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_dmic0_cap_ops,
@@ -565,7 +565,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "dmic1",
.stream_name = "DMIC1 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_dmic1_cap_ops,
@@ -578,7 +578,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.name = "amd-rt5682-play",
.stream_name = "Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.init = cz_rt5682_init,
.dpcm_playback = 1,
.stop_dma_first = 1,
@@ -589,7 +589,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.name = "amd-rt5682-cap",
.stream_name = "Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_cap_ops,
@@ -599,7 +599,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.name = "amd-max98357-play",
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_playback = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_max_play_ops,
@@ -610,7 +610,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.name = "dmic0",
.stream_name = "DMIC0 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_dmic0_cap_ops,
@@ -621,7 +621,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.name = "dmic1",
.stream_name = "DMIC1 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_dmic1_cap_ops,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 1f322accd9ea..1cd2e70a57df 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -1003,6 +1003,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
+ struct audio_drv_data *adata = dev_get_drvdata(component->dev);
if (!rtd)
return -EINVAL;
@@ -1023,7 +1024,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
}
if (bytescount > 0) {
delay = do_div(bytescount, period_bytes);
- runtime->delay = bytes_to_frames(runtime, delay);
+ adata->delay += bytes_to_frames(runtime, delay);
}
} else {
buffersize = frames_to_bytes(runtime, runtime->buffer_size);
@@ -1035,6 +1036,17 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
return bytes_to_frames(runtime, pos);
}
+static snd_pcm_sframes_t acp_dma_delay(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct audio_drv_data *adata = dev_get_drvdata(component->dev);
+ snd_pcm_sframes_t delay = adata->delay;
+
+ adata->delay = 0;
+
+ return delay;
+}
+
static int acp_dma_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -1198,15 +1210,15 @@ static const struct snd_soc_component_driver acp_asoc_platform = {
.hw_params = acp_dma_hw_params,
.trigger = acp_dma_trigger,
.pointer = acp_dma_pointer,
+ .delay = acp_dma_delay,
.prepare = acp_dma_prepare,
.pcm_construct = acp_dma_new,
};
static int acp_audio_probe(struct platform_device *pdev)
{
- int status;
+ int status, irq;
struct audio_drv_data *audio_drv_data;
- struct resource *res;
const u32 *pdata = pdev->dev.platform_data;
if (!pdata) {
@@ -1236,13 +1248,11 @@ static int acp_audio_probe(struct platform_device *pdev)
audio_drv_data->asic_type = *pdata;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
return -ENODEV;
- }
- status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler,
+ status = devm_request_irq(&pdev->dev, irq, dma_irq_handler,
0, "ACP_IRQ", &pdev->dev);
if (status) {
dev_err(&pdev->dev, "ACP IRQ request failed\n");
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
index 6d5c547a32de..532aa98a2241 100644
--- a/sound/soc/amd/acp-rt5645.c
+++ b/sound/soc/amd/acp-rt5645.c
@@ -80,7 +80,7 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack, NULL, 0);
+ &cz_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -111,7 +111,7 @@ static struct snd_soc_dai_link cz_dai_rt5650[] = {
.name = "amd-rt5645-play",
.stream_name = "RT5645_AIF1",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.init = cz_init,
.ops = &cz_aif1_ops,
SND_SOC_DAILINK_REG(designware1, codec, platform),
@@ -120,7 +120,7 @@ static struct snd_soc_dai_link cz_dai_rt5650[] = {
.name = "amd-rt5645-cap",
.stream_name = "RT5645_AIF1",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ops = &cz_aif1_ops,
SND_SOC_DAILINK_REG(designware2, codec, platform),
},
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index 85529ed7e5f5..db80a73aa593 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -151,6 +151,7 @@ struct audio_drv_data {
struct snd_pcm_substream *capture_i2sbt_stream;
void __iomem *acp_mmio;
u32 asic_type;
+ snd_pcm_sframes_t delay;
};
/*
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig
index 52a1371f9e61..9dae2719084c 100644
--- a/sound/soc/amd/acp/Kconfig
+++ b/sound/soc/amd/acp/Kconfig
@@ -15,6 +15,9 @@ config SND_SOC_AMD_ACP_COMMON
if SND_SOC_AMD_ACP_COMMON
+config SND_SOC_AMD_ACP_PDM
+ tristate
+
config SND_SOC_AMD_ACP_I2S
tristate
@@ -22,10 +25,17 @@ config SND_SOC_AMD_ACP_PCM
tristate
select SND_SOC_ACPI if ACPI
+config SND_SOC_AMD_ACP_PCI
+ tristate "AMD ACP PCI Driver Support"
+ depends on X86 && PCI
+ help
+ This options enables generic PCI driver for ACP device.
+
config SND_AMD_ASOC_RENOIR
tristate "AMD ACP ASOC Renoir Support"
select SND_SOC_AMD_ACP_PCM
select SND_SOC_AMD_ACP_I2S
+ select SND_SOC_AMD_ACP_PDM
depends on X86 && PCI
help
This option enables Renoir I2S support on AMD platform.
@@ -46,7 +56,6 @@ config SND_SOC_AMD_LEGACY_MACH
tristate "AMD Legacy Machine Driver Support"
depends on X86 && PCI && I2C
select SND_SOC_AMD_MACH_COMMON
- depends on X86 && PCI && I2C
help
This option enables legacy sound card support for ACP audio.
@@ -54,7 +63,6 @@ config SND_SOC_AMD_SOF_MACH
tristate "AMD SOF Machine Driver Support"
depends on X86 && PCI && I2C
select SND_SOC_AMD_MACH_COMMON
- depends on X86 && PCI && I2C
help
This option enables SOF sound card support for ACP audio.
diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile
index 16c144c2965c..657ddfadf0bb 100644
--- a/sound/soc/amd/acp/Makefile
+++ b/sound/soc/amd/acp/Makefile
@@ -7,6 +7,8 @@
#common acp driver
snd-acp-pcm-objs := acp-platform.o
snd-acp-i2s-objs := acp-i2s.o
+snd-acp-pdm-objs := acp-pdm.o
+snd-acp-pci-objs := acp-pci.o
#platform specific driver
snd-acp-renoir-objs := acp-renoir.o
@@ -18,6 +20,8 @@ snd-acp-sof-mach-objs := acp-sof-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o
obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o
+obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
+obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o
obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index de0f8024e2fb..7f04a048ca3a 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -23,10 +23,28 @@
static struct acp_card_drvdata rt5682_rt1019_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
- .dmic_cpu_id = NONE,
+ .dmic_cpu_id = DMIC,
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
- .dmic_codec_id = NONE,
+ .dmic_codec_id = DMIC,
+};
+
+static struct acp_card_drvdata rt5682s_max_data = {
+ .hs_cpu_id = I2S_SP,
+ .amp_cpu_id = I2S_SP,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = RT5682S,
+ .amp_codec_id = MAX98360A,
+ .dmic_codec_id = DMIC,
+};
+
+static struct acp_card_drvdata rt5682s_rt1019_data = {
+ .hs_cpu_id = I2S_SP,
+ .amp_cpu_id = I2S_SP,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = RT5682S,
+ .amp_codec_id = RT1019,
+ .dmic_codec_id = DMIC,
};
static const struct snd_kcontrol_new acp_controls[] = {
@@ -83,13 +101,22 @@ static int acp_asoc_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
- .name = "rn_rt5682_rt1019",
+ .name = "acp3xalc56821019",
.driver_data = (kernel_ulong_t)&rt5682_rt1019_data,
},
+ {
+ .name = "acp3xalc5682sm98360",
+ .driver_data = (kernel_ulong_t)&rt5682s_max_data,
+ },
+ {
+ .name = "acp3xalc5682s1019",
+ .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data,
+ },
{ }
};
static struct platform_driver acp_asoc_audio = {
.driver = {
+ .pm = &snd_soc_pm_ops,
.name = "acp_mach",
},
.probe = acp_asoc_probe,
@@ -100,5 +127,7 @@ module_platform_driver(acp_asoc_audio);
MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
MODULE_DESCRIPTION("ACP chrome audio support");
-MODULE_ALIAS("platform:rn_rt5682_rt1019");
+MODULE_ALIAS("platform:acp3xalc56821019");
+MODULE_ALIAS("platform:acp3xalc5682sm98360");
+MODULE_ALIAS("platform:acp3xalc5682s1019");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 7785f12aa006..6ae454bf60af 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -120,7 +120,7 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack, NULL, 0);
+ &pco_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -241,7 +241,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack, NULL, 0);
+ &pco_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -266,10 +266,36 @@ static const struct snd_soc_ops acp_card_rt5682s_ops = {
.shutdown = acp_card_shutdown,
};
+static const unsigned int dmic_channels[] = {
+ DUAL_CHANNEL, FOUR_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list dmic_constraints_channels = {
+ .count = ARRAY_SIZE(dmic_channels),
+ .list = dmic_channels,
+ .mask = 0,
+};
+
+static int acp_card_dmic_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &dmic_constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+
+ return 0;
+}
+
+static const struct snd_soc_ops acp_card_dmic_ops = {
+ .startup = acp_card_dmic_startup,
+};
+
/* Declare RT1019 codec components */
SND_SOC_DAILINK_DEF(rt1019,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"),
- COMP_CODEC("i2c-10EC1019:02", "rt1019-aif")));
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
+ COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
{ "Left Spk", NULL, "Left SPO" },
@@ -282,7 +308,7 @@ static struct snd_soc_codec_conf rt1019_conf[] = {
.name_prefix = "Left",
},
{
- .dlc = COMP_CODEC_CONF("i2c-10EC1019:02"),
+ .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
.name_prefix = "Right",
},
};
@@ -413,6 +439,8 @@ SND_SOC_DAILINK_DEF(sof_sp,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
SND_SOC_DAILINK_DEF(sof_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
+SND_SOC_DAILINK_DEF(pdm_dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic")));
int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
{
@@ -531,6 +559,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
num_links++;
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
+ if (!links)
+ return -ENOMEM;
if (drv_data->hs_cpu_id == I2S_SP) {
links[i].name = "acp-headset-codec";
@@ -588,6 +618,26 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].ops = &acp_card_maxim_ops;
links[i].init = acp_card_maxim_init;
}
+ i++;
+ }
+
+ if (drv_data->dmic_cpu_id == DMIC) {
+ links[i].name = "acp-dmic-codec";
+ links[i].id = DMIC_BE_ID;
+ if (drv_data->dmic_codec_id == DMIC) {
+ links[i].codecs = dmic_codec;
+ links[i].num_codecs = ARRAY_SIZE(dmic_codec);
+ } else {
+ /* Use dummy codec if codec id not specified */
+ links[i].codecs = dummy_codec;
+ links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+ }
+ links[i].cpus = pdm_dmic;
+ links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
+ links[i].platforms = platform_component;
+ links[i].num_platforms = ARRAY_SIZE(platform_component);
+ links[i].ops = &acp_card_dmic_ops;
+ links[i].dpcm_capture = 1;
}
card->dai_link = links;
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
new file mode 100644
index 000000000000..c893963ee2d0
--- /dev/null
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+
+/*
+ * Generic PCI interface for ACP device
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#include "amd.h"
+#include "../mach-config.h"
+
+#define DRV_NAME "acp_pci"
+
+#define ACP3x_REG_START 0x1240000
+#define ACP3x_REG_END 0x125C000
+
+static struct platform_device *dmic_dev;
+static struct platform_device *pdev;
+
+static const struct resource acp3x_res[] = {
+ {
+ .start = 0,
+ .end = ACP3x_REG_END - ACP3x_REG_START,
+ .name = "acp_mem",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .name = "acp_dai_irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ struct platform_device_info pdevinfo;
+ struct device *dev = &pci->dev;
+ const struct resource *res_acp;
+ struct acp_chip_info *chip;
+ struct resource *res;
+ unsigned int flag, addr, num_res, i;
+ int ret;
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_LEGACY)
+ return -ENODEV;
+
+ chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ if (pci_enable_device(pci)) {
+ dev_err(&pci->dev, "pci_enable_device failed\n");
+ return -ENODEV;
+ }
+
+ ret = pci_request_regions(pci, "AMD ACP3x audio");
+ if (ret < 0) {
+ dev_err(&pci->dev, "pci_request_regions failed\n");
+ return -ENOMEM;
+ }
+
+ pci_set_master(pci);
+
+ switch (pci->revision) {
+ case 0x01:
+ res_acp = acp3x_res;
+ num_res = ARRAY_SIZE(acp3x_res);
+ chip->name = "acp_asoc_renoir";
+ chip->acp_rev = ACP3X_DEV;
+ break;
+ default:
+ dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
+ return -EINVAL;
+ }
+
+ dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(dmic_dev)) {
+ dev_err(dev, "failed to create DMIC device\n");
+ return PTR_ERR(dmic_dev);
+ }
+
+ addr = pci_resource_start(pci, 0);
+ chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
+
+ res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL);
+ if (!res) {
+ platform_device_unregister(dmic_dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_res; i++, res_acp++) {
+ res[i].name = res_acp->name;
+ res[i].flags = res_acp->flags;
+ res[i].start = addr + res_acp->start;
+ res[i].end = addr + res_acp->end;
+ if (res_acp->flags == IORESOURCE_IRQ) {
+ res[i].start = pci->irq;
+ res[i].end = res[i].start;
+ }
+ }
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+
+ pdevinfo.name = chip->name;
+ pdevinfo.id = 0;
+ pdevinfo.parent = &pci->dev;
+ pdevinfo.num_res = num_res;
+ pdevinfo.res = &res[0];
+ pdevinfo.data = chip;
+ pdevinfo.size_data = sizeof(*chip);
+
+ pdev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(pdev)) {
+ dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
+ platform_device_unregister(dmic_dev);
+ ret = PTR_ERR(pdev);
+ }
+
+ return ret;
+};
+
+static void acp_pci_remove(struct pci_dev *pci)
+{
+ if (dmic_dev)
+ platform_device_unregister(dmic_dev);
+ if (pdev)
+ platform_device_unregister(pdev);
+}
+
+/* PCI IDs */
+static const struct pci_device_id acp_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID)},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, acp_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_amd_acp_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = acp_pci_ids,
+ .probe = acp_pci_probe,
+ .remove = acp_pci_remove,
+};
+module_pci_driver(snd_amd_acp_pci_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c
new file mode 100644
index 000000000000..424c6e0bb9d6
--- /dev/null
+++ b/sound/soc/amd/acp/acp-pdm.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Advanced Micro Devices, Inc.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+// Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+//
+
+/*
+ * Generic Hardware interface for ACP Audio PDM controller
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "amd.h"
+
+#define DRV_NAME "acp-pdm"
+
+#define PDM_DMA_STAT 0x10
+#define PDM_DMA_INTR_MASK 0x10000
+#define PDM_DEC_64 0x2
+#define PDM_CLK_FREQ_MASK 0x07
+#define PDM_MISC_CTRL_MASK 0x10
+#define PDM_ENABLE 0x01
+#define PDM_DISABLE 0x00
+#define DMA_EN_MASK 0x02
+#define DELAY_US 5
+#define PDM_TIMEOUT 1000
+#define ACP_REGION2_OFFSET 0x02000000
+
+static int acp_dmic_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct acp_stream *stream = substream->runtime->private_data;
+ struct device *dev = dai->component->dev;
+ struct acp_dev_data *adata = dev_get_drvdata(dev);
+ u32 physical_addr, size_dmic, period_bytes;
+ unsigned int dmic_ctrl;
+
+ /* Enable default DMIC clk */
+ writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);
+ dmic_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);
+ dmic_ctrl |= PDM_MISC_CTRL_MASK;
+ writel(dmic_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL);
+
+ period_bytes = frames_to_bytes(substream->runtime,
+ substream->runtime->period_size);
+ size_dmic = frames_to_bytes(substream->runtime,
+ substream->runtime->buffer_size);
+
+ physical_addr = stream->reg_offset + MEM_WINDOW_START;
+
+ /* Init DMIC Ring buffer */
+ writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);
+ writel(size_dmic, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE);
+ writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+ writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
+
+ return 0;
+}
+
+static int acp_dmic_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct device *dev = dai->component->dev;
+ struct acp_dev_data *adata = dev_get_drvdata(dev);
+ unsigned int dma_enable;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ if (!(dma_enable & DMA_EN_MASK)) {
+ writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_ENABLE);
+ writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ }
+
+ ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE,
+ dma_enable, (dma_enable & DMA_EN_MASK),
+ DELAY_US, PDM_TIMEOUT);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ if ((dma_enable & DMA_EN_MASK)) {
+ writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_ENABLE);
+ writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+
+ }
+
+ ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE,
+ dma_enable, !(dma_enable & DMA_EN_MASK),
+ DELAY_US, PDM_TIMEOUT);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int acp_dmic_hwparams(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hwparams, struct snd_soc_dai *dai)
+{
+ struct device *dev = dai->component->dev;
+ struct acp_dev_data *adata = dev_get_drvdata(dev);
+ unsigned int channels, ch_mask;
+
+ channels = params_channels(hwparams);
+ switch (channels) {
+ case 2:
+ ch_mask = 0;
+ break;
+ case 4:
+ ch_mask = 1;
+ break;
+ case 6:
+ ch_mask = 2;
+ break;
+ default:
+ dev_err(dev, "Invalid channels %d\n", channels);
+ return -EINVAL;
+ }
+
+ if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) {
+ dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams));
+ return -EINVAL;
+ }
+
+ writel(ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+
+ return 0;
+}
+
+static int acp_dmic_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct acp_stream *stream = substream->runtime->private_data;
+ struct device *dev = dai->component->dev;
+ struct acp_dev_data *adata = dev_get_drvdata(dev);
+ u32 ext_int_ctrl;
+
+ stream->dai_id = DMIC_INSTANCE;
+ stream->irq_bit = BIT(PDM_DMA_STAT);
+ stream->pte_offset = ACP_SRAM_PDM_PTE_OFFSET;
+ stream->reg_offset = ACP_REGION2_OFFSET;
+
+ /* Enable DMIC Interrupts */
+ ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_int_ctrl |= PDM_DMA_INTR_MASK;
+ writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+
+ return 0;
+}
+
+static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = dai->component->dev;
+ struct acp_dev_data *adata = dev_get_drvdata(dev);
+ u32 ext_int_ctrl;
+
+ /* Disable DMIC interrrupts */
+ ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_int_ctrl |= ~PDM_DMA_INTR_MASK;
+ writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+}
+
+const struct snd_soc_dai_ops acp_dmic_dai_ops = {
+ .prepare = acp_dmic_prepare,
+ .hw_params = acp_dmic_hwparams,
+ .trigger = acp_dmic_dai_trigger,
+ .startup = acp_dmic_dai_startup,
+ .shutdown = acp_dmic_dai_shutdown,
+};
+EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, SND_SOC_ACP_COMMON);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c
index 9b321a055b52..75c9229ece97 100644
--- a/sound/soc/amd/acp/acp-renoir.c
+++ b/sound/soc/amd/acp/acp-renoir.c
@@ -25,15 +25,46 @@
#define DRV_NAME "acp_asoc_renoir"
+#define ACP_SOFT_RST_DONE_MASK 0x00010001
+
+#define ACP_PWR_ON_MASK 0x01
+#define ACP_PWR_OFF_MASK 0x00
+#define ACP_PGFSM_STAT_MASK 0x03
+#define ACP_POWERED_ON 0x00
+#define ACP_PWR_ON_IN_PROGRESS 0x01
+#define ACP_POWERED_OFF 0x02
+#define DELAY_US 5
+#define ACP_TIMEOUT 500
+
+#define ACP_ERROR_MASK 0x20000000
+#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
+
static struct snd_soc_acpi_codecs amp_rt1019 = {
.num_codecs = 1,
.codecs = {"10EC1019"}
};
+static struct snd_soc_acpi_codecs amp_max = {
+ .num_codecs = 1,
+ .codecs = {"MX98360A"}
+};
+
static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = {
{
.id = "10EC5682",
- .drv_name = "rn_rt5682_rt1019",
+ .drv_name = "acp3xalc56821019",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "acp3xalc5682sm98360",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max,
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "acp3xalc5682s1019",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &amp_rt1019,
},
@@ -97,13 +128,145 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
.ops = &asoc_acp_cpu_dai_ops,
.probe = &asoc_acp_i2s_probe,
},
+{
+ .name = "acp-pdm-dmic",
+ .id = DMIC_INSTANCE,
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &acp_dmic_dai_ops,
+},
};
+static int acp3x_power_on(void __iomem *base)
+{
+ u32 val;
+
+ val = readl(base + ACP_PGFSM_STATUS);
+
+ if (val == ACP_POWERED_ON)
+ return 0;
+
+ if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS)
+ writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL);
+
+ return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
+}
+
+static int acp3x_power_off(void __iomem *base)
+{
+ u32 val;
+
+ writel(ACP_PWR_OFF_MASK, base + ACP_PGFSM_CONTROL);
+
+ return readl_poll_timeout(base + ACP_PGFSM_STATUS, val,
+ (val & ACP_PGFSM_STAT_MASK) == ACP_POWERED_OFF,
+ DELAY_US, ACP_TIMEOUT);
+}
+
+static int acp3x_reset(void __iomem *base)
+{
+ u32 val;
+ int ret;
+
+ writel(1, base + ACP_SOFT_RESET);
+
+ ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
+ DELAY_US, ACP_TIMEOUT);
+ if (ret)
+ return ret;
+
+ writel(0, base + ACP_SOFT_RESET);
+
+ return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
+}
+
+static void acp3x_enable_interrupts(void __iomem *base)
+{
+ u32 ext_intr_ctrl;
+
+ writel(0x01, base + ACP_EXTERNAL_INTR_ENB);
+ ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL);
+ ext_intr_ctrl |= ACP_ERROR_MASK;
+ writel(ext_intr_ctrl, base + ACP_EXTERNAL_INTR_CNTL);
+}
+
+static void acp3x_disable_interrupts(void __iomem *base)
+{
+ writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + ACP_EXTERNAL_INTR_STAT);
+ writel(0x00, base + ACP_EXTERNAL_INTR_ENB);
+}
+
+static int rn_acp_init(void __iomem *base)
+{
+ int ret;
+
+ /* power on */
+ ret = acp3x_power_on(base);
+ if (ret)
+ return ret;
+
+ writel(0x01, base + ACP_CONTROL);
+
+ /* Reset */
+ ret = acp3x_reset(base);
+ if (ret)
+ return ret;
+
+ acp3x_enable_interrupts(base);
+
+ return 0;
+}
+
+static int rn_acp_deinit(void __iomem *base)
+{
+ int ret = 0;
+
+ acp3x_disable_interrupts(base);
+
+ /* Reset */
+ ret = acp3x_reset(base);
+ if (ret)
+ return ret;
+
+ writel(0x00, base + ACP_CONTROL);
+
+ /* power off */
+ ret = acp3x_power_off(base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
static int renoir_audio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct acp_chip_info *chip;
struct acp_dev_data *adata;
struct resource *res;
+ int ret;
+
+ chip = dev_get_platdata(&pdev->dev);
+ if (!chip || !chip->base) {
+ dev_err(&pdev->dev, "ACP chip data is NULL\n");
+ return -ENODEV;
+ }
+
+ if (chip->acp_rev != ACP3X_DEV) {
+ dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
+ return -ENODEV;
+ }
+
+ ret = rn_acp_init(chip->base);
+ if (ret) {
+ dev_err(&pdev->dev, "ACP Init failed\n");
+ return -EINVAL;
+ }
adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
if (!adata)
@@ -119,13 +282,11 @@ static int renoir_audio_probe(struct platform_device *pdev)
if (!adata->acp_base)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
+ ret = platform_get_irq_byname(pdev, "acp_dai_irq");
+ if (ret < 0)
+ return ret;
+ adata->i2s_irq = ret;
- adata->i2s_irq = res->start;
adata->dev = dev;
adata->dai_driver = acp_renoir_dai;
adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
@@ -142,6 +303,20 @@ static int renoir_audio_probe(struct platform_device *pdev)
static int renoir_audio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct acp_chip_info *chip;
+ int ret;
+
+ chip = dev_get_platdata(&pdev->dev);
+ if (!chip || !chip->base) {
+ dev_err(&pdev->dev, "ACP chip data is NULL\n");
+ return -ENODEV;
+ }
+
+ ret = rn_acp_deinit(chip->base);
+ if (ret) {
+ dev_err(&pdev->dev, "ACP de-init Failed\n");
+ return -EINVAL;
+ }
acp_platform_unregister(dev);
return 0;
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 854eb7214cea..d1531cdab110 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -38,6 +38,15 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
.dmic_codec_id = DMIC,
};
+static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
+ .hs_cpu_id = I2S_SP,
+ .amp_cpu_id = I2S_SP,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = RT5682S,
+ .amp_codec_id = RT1019,
+ .dmic_codec_id = DMIC,
+};
+
static struct acp_card_drvdata sof_rt5682s_max_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
@@ -111,11 +120,16 @@ static const struct platform_device_id board_ids[] = {
.name = "rt5682s-max",
.driver_data = (kernel_ulong_t)&sof_rt5682s_max_data
},
+ {
+ .name = "rt5682s-rt1019",
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
+ },
{ }
};
static struct platform_driver acp_asoc_audio = {
.driver = {
.name = "sof_mach",
+ .pm = &snd_soc_pm_ops,
},
.probe = acp_sof_probe,
.id_table = board_ids,
@@ -128,4 +142,5 @@ MODULE_DESCRIPTION("ACP chrome SOF audio support");
MODULE_ALIAS("platform:rt5682-rt1019");
MODULE_ALIAS("platform:rt5682-max");
MODULE_ALIAS("platform:rt5682s-max");
+MODULE_ALIAS("platform:rt5682s-rt1019");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index 8eee3d34774b..8fd38bf4d3bd 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -12,13 +12,19 @@
#define __AMD_ACP_H
#include <sound/pcm.h>
+#include <sound/soc.h>
#include <sound/soc-acpi.h>
+#include <sound/soc-dai.h>
+
#include "chip_offset_byte.h"
+#define ACP3X_DEV 3
+
#define I2S_SP_INSTANCE 0x00
#define I2S_BT_INSTANCE 0x01
+#define DMIC_INSTANCE 0x02
-#define MEM_WINDOW_START 0x4000000
+#define MEM_WINDOW_START 0x4080000
#define ACP_I2S_REG_START 0x1242400
#define ACP_I2S_REG_END 0x1242810
@@ -38,6 +44,7 @@
#define ACP_SRAM_SP_CP_PTE_OFFSET 0x100
#define ACP_SRAM_BT_PB_PTE_OFFSET 0x200
#define ACP_SRAM_BT_CP_PTE_OFFSET 0x300
+#define ACP_SRAM_PDM_PTE_OFFSET 0x400
#define PAGE_SIZE_4K_ENABLE 0x2
#define I2S_SP_TX_MEM_WINDOW_START 0x4000000
@@ -68,6 +75,12 @@
#define ACP_MAX_STREAM 6
+struct acp_chip_info {
+ char *name; /* Platform name */
+ unsigned int acp_rev; /* ACP Revision id */
+ void __iomem *base; /* ACP memory PCI base */
+};
+
struct acp_stream {
struct snd_pcm_substream *substream;
int irq_bit;
@@ -96,6 +109,7 @@ struct acp_dev_data {
};
extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
+extern const struct snd_soc_dai_ops acp_dmic_dai_ops;
int asoc_acp_i2s_probe(struct snd_soc_dai *dai);
int acp_platform_register(struct device *dev);
@@ -103,6 +117,9 @@ int acp_platform_unregister(struct device *dev);
int acp_machine_select(struct acp_dev_data *adata);
+/* Machine configuration */
+int snd_amd_acp_find_config(struct pci_dev *pci);
+
static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
{
u64 byte_count, low = 0, high = 0;
@@ -131,6 +148,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
break;
+ case DMIC_INSTANCE:
+ high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
+ low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
+ break;
default:
dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
return -EINVAL;
diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h
index c7f77e975dc7..88f6fa597cd6 100644
--- a/sound/soc/amd/acp/chip_offset_byte.h
+++ b/sound/soc/amd/acp/chip_offset_byte.h
@@ -14,6 +14,12 @@
#define ACPAXI2AXI_ATU_CTRL 0xC40
#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24
+
+#define ACP_PGFSM_CONTROL 0x141C
+#define ACP_PGFSM_STATUS 0x1420
+#define ACP_SOFT_RESET 0x1000
+#define ACP_CONTROL 0x1004
+
#define ACP_EXTERNAL_INTR_ENB 0x1800
#define ACP_EXTERNAL_INTR_CNTL 0x1804
#define ACP_EXTERNAL_INTR_STAT 0x1808
@@ -73,4 +79,24 @@
#define ACP_BTTDM_ITER 0x280C
#define ACP_BTTDM_TXFRMT 0x2810
+/* Registers from ACP_WOV_PDM block */
+
+#define ACP_WOV_PDM_ENABLE 0x2C04
+#define ACP_WOV_PDM_DMA_ENABLE 0x2C08
+#define ACP_WOV_RX_RINGBUFADDR 0x2C0C
+#define ACP_WOV_RX_RINGBUFSIZE 0x2C10
+#define ACP_WOV_RX_LINKPOSITIONCNTR 0x2C14
+#define ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH 0x2C18
+#define ACP_WOV_RX_LINEARPOSITIONCNTR_LOW 0x2C1C
+#define ACP_WOV_RX_INTR_WATERMARK_SIZE 0x2C20
+#define ACP_WOV_PDM_FIFO_FLUSH 0x2C24
+#define ACP_WOV_PDM_NO_OF_CHANNELS 0x2C28
+#define ACP_WOV_PDM_DECIMATION_FACTOR 0x2C2C
+#define ACP_WOV_PDM_VAD_CTRL 0x2C30
+#define ACP_WOV_BUFFER_STATUS 0x2C58
+#define ACP_WOV_MISC_CTRL 0x2C5C
+#define ACP_WOV_CLK_CTRL 0x2C60
+#define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN 0x2C64
+#define ACP_WOV_ERROR_STATUS_REGISTER 0x2C68
+
#endif
diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index e561464f7d60..0543dda75b99 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -51,7 +51,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
/* set rt5682 dai fmt */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
+ | SND_SOC_DAIFMT_CBP_CFP);
if (ret < 0) {
dev_err(rtd->card->dev,
"Failed to set rt5682 dai fmt: %d\n", ret);
@@ -90,7 +90,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack, NULL, 0);
+ &pco_jack);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -302,7 +302,7 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.name = "acp3x-5682-play",
.stream_name = "Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.init = acp3x_5682_init,
.dpcm_playback = 1,
.dpcm_capture = 1,
@@ -313,7 +313,7 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.name = "acp3x-max98357-play",
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBS_CFS,
+ | SND_SOC_DAIFMT_CBC_CFC,
.dpcm_playback = 1,
.ops = &acp3x_max_play_ops,
.cpus = acp3x_bt,
@@ -325,7 +325,7 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.name = "acp3x-ec-dmic0-capture",
.stream_name = "Capture DMIC0",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBS_CFS,
+ | SND_SOC_DAIFMT_CBC_CFC,
.dpcm_capture = 1,
.ops = &acp3x_ec_cap0_ops,
SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform),
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
new file mode 100644
index 000000000000..0a54567a2841
--- /dev/null
+++ b/sound/soc/amd/mach-config.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+ */
+#ifndef __AMD_MACH_CONFIG_H
+#define __AMD_MACH_CONFIG_H
+
+#include <sound/soc-acpi.h>
+
+#define FLAG_AMD_SOF BIT(1)
+#define FLAG_AMD_SOF_ONLY_DMIC BIT(2)
+#define FLAG_AMD_LEGACY BIT(3)
+
+#define ACP_PCI_DEV_ID 0x15E2
+
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[];
+
+struct config_entry {
+ u32 flags;
+ u16 device;
+ const struct dmi_system_id *dmi_table;
+};
+
+#endif
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 75c06697fa09..6aec11cf0a6a 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -394,13 +394,10 @@ static int acp3x_audio_probe(struct platform_device *pdev)
if (!adata->acp3x_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
-
- adata->i2s_irq = res->start;
+ status = platform_get_irq(pdev, 0);
+ if (status < 0)
+ return status;
+ adata->i2s_irq = status;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h
index c3f0c8b7545d..7702f628ecd6 100644
--- a/sound/soc/amd/raven/acp3x.h
+++ b/sound/soc/amd/raven/acp3x.h
@@ -87,7 +87,7 @@ struct acp3x_platform_info {
struct i2s_dev_data {
bool tdm_mode;
- unsigned int i2s_irq;
+ int i2s_irq;
u16 i2s_instance;
u32 tdm_fmt;
u32 substream_type;
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index 9dd22a2fa2e5..8c42345ee41e 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -399,13 +399,11 @@ static int acp_pdm_audio_probe(struct platform_device *pdev)
if (!adata->acp_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
+ status = platform_get_irq(pdev, 0);
+ if (status < 0)
+ return status;
+ adata->pdm_irq = status;
- adata->pdm_irq = res->start;
adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata);
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c
index 7b8040e812a1..b3812b70f5f9 100644
--- a/sound/soc/amd/renoir/rn-pci-acp3x.c
+++ b/sound/soc/amd/renoir/rn-pci-acp3x.c
@@ -212,10 +212,15 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
acpi_integer dmic_status;
#endif
const struct dmi_system_id *dmi_id;
- unsigned int irqflags;
+ unsigned int irqflags, flag;
int ret, index;
u32 addr;
+ /* Return if acp config flag is defined */
+ flag = snd_amd_acp_find_config(pci);
+ if (flag)
+ return -ENODEV;
+
/* Renoir device check */
if (pci->revision != 0x01)
return -ENODEV;
diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h
index 14620399d766..ca586603d720 100644
--- a/sound/soc/amd/renoir/rn_acp3x.h
+++ b/sound/soc/amd/renoir/rn_acp3x.h
@@ -88,3 +88,6 @@ static inline void rn_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr - ACP_PHY_BASE_ADDRESS);
}
+
+/* Machine configuration */
+int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index 002db3971ca9..59a98f89a669 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -88,10 +88,9 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_soc_card *card;
struct acp5x_platform_info *pinfo;
struct i2s_dev_data *adata;
- union acp_i2stdm_mstrclkgen mclkgen;
u32 val;
- u32 reg_val, frmt_reg, master_reg;
+ u32 reg_val, frmt_reg;
u32 lrclk_div_val, bclk_div_val;
lrclk_div_val = 0;
@@ -160,20 +159,6 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
acp_writel(val, rtd->acp5x_base + reg_val);
if (adata->master_mode) {
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- master_reg = ACP_I2STDM2_MSTRCLKGEN;
- break;
- case I2S_SP_INSTANCE:
- default:
- master_reg = ACP_I2STDM0_MSTRCLKGEN;
- break;
- }
- mclkgen.bits.i2stdm_master_mode = 0x1;
- if (adata->tdm_mode)
- mclkgen.bits.i2stdm_format_mode = 0x01;
- else
- mclkgen.bits.i2stdm_format_mode = 0x0;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
switch (params_rate(params)) {
@@ -238,9 +223,8 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
default:
return -EINVAL;
}
- mclkgen.bits.i2stdm_bclk_div_val = bclk_div_val;
- mclkgen.bits.i2stdm_lrclk_div_val = lrclk_div_val;
- acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg);
+ rtd->lrclk_div = lrclk_div_val;
+ rtd->bclk_div = bclk_div_val;
}
return 0;
}
@@ -249,9 +233,11 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct i2s_stream_instance *rtd;
+ struct i2s_dev_data *adata;
u32 ret, val, period_bytes, reg_val, ier_val, water_val;
u32 buf_size, buf_reg;
+ adata = snd_soc_dai_get_drvdata(dai);
rtd = substream->runtime->private_data;
period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size);
@@ -300,6 +286,8 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
}
acp_writel(period_bytes, rtd->acp5x_base + water_val);
acp_writel(buf_size, rtd->acp5x_base + buf_reg);
+ if (adata->master_mode)
+ acp5x_set_i2s_clk(adata, rtd);
val = acp_readl(rtd->acp5x_base + reg_val);
val = val | BIT(0);
acp_writel(val, rtd->acp5x_base + reg_val);
diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c
index 14cf325e4b23..727de46860b1 100644
--- a/sound/soc/amd/vangogh/acp5x-mach.c
+++ b/sound/soc/amd/vangogh/acp5x-mach.c
@@ -17,10 +17,8 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
-#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
-#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
@@ -33,6 +31,8 @@
#define DUAL_CHANNEL 2
#define ACP5X_NUVOTON_CODEC_DAI "nau8821-hifi"
#define VG_JUPITER 1
+#define ACP5X_NUVOTON_BCLK 3072000
+#define ACP5X_NAU8821_FREQ_OUT 12288000
static unsigned long acp5x_machine_id;
static struct snd_soc_jack vg_headset;
@@ -59,10 +59,10 @@ static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
- &vg_headset, acp5x_nau8821_jack_pins,
- ARRAY_SIZE(acp5x_nau8821_jack_pins));
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &vg_headset, acp5x_nau8821_jack_pins,
+ ARRAY_SIZE(acp5x_nau8821_jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
@@ -98,10 +98,17 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
+static const unsigned int acp5x_nau8821_format[] = {32};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
+ .list = acp5x_nau8821_format,
+ .count = ARRAY_SIZE(acp5x_nau8821_format),
+};
+
static int acp5x_8821_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -113,13 +120,16 @@ static int acp5x_8821_startup(struct snd_pcm_substream *substream)
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ &constraints_sample_bits);
return 0;
}
static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai =
snd_soc_card_get_codec_dai(card,
@@ -141,7 +151,7 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -158,13 +168,14 @@ static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai;
int ret, i;
unsigned int num_codecs = rtd->num_codecs;
unsigned int bclk_val;
+ ret = 0;
for (i = 0; i < num_codecs; i++) {
codec_dai = asoc_rtd_to_codec(rtd, i);
if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) ||
@@ -230,7 +241,7 @@ SND_SOC_DAILINK_DEF(platform,
static struct snd_soc_dai_link acp5x_dai[] = {
{
- .name = "acp5x-8825-play",
+ .name = "acp5x-8821-play",
.stream_name = "Playback/Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
@@ -274,6 +285,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
dev_err(card->dev, "set sysclk err = %d\n", ret);
return -EIO;
}
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set BLK clock %d\n", ret);
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, ACP5X_NUVOTON_BCLK,
+ ACP5X_NAU8821_FREQ_OUT);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
}
return ret;
}
@@ -289,7 +309,7 @@ static const struct snd_soc_dapm_widget acp5x_8821_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_POST_PMD),
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route acp5x_8821_audio_route[] = {
@@ -320,7 +340,6 @@ static struct snd_soc_card acp5x_card = {
.num_controls = ARRAY_SIZE(acp5x_8821_controls),
};
-
static int acp5x_vg_quirk_cb(const struct dmi_system_id *id)
{
acp5x_machine_id = VG_JUPITER;
@@ -350,7 +369,7 @@ static int acp5x_probe(struct platform_device *pdev)
return -ENOMEM;
dmi_check_system(acp5x_vg_quirk_table);
- switch(acp5x_machine_id) {
+ switch (acp5x_machine_id) {
case VG_JUPITER:
card = &acp5x_card;
acp5x_card.dev = &pdev->dev;
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index f10de38976cb..d36bb718370f 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -281,7 +281,7 @@ static int acp5x_dma_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
size = params_buffer_bytes(params);
- rtd->dma_addr = substream->dma_buffer.addr;
+ rtd->dma_addr = substream->runtime->dma_addr;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
config_acp5x_dma(rtd, substream->stream);
return 0;
@@ -388,13 +388,11 @@ static int acp5x_audio_probe(struct platform_device *pdev)
if (!adata->acp5x_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
+ status = platform_get_irq(pdev, 0);
+ if (status < 0)
+ return status;
+ adata->i2s_irq = status;
- adata->i2s_irq = res->start;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
&acp5x_i2s_component,
@@ -426,51 +424,51 @@ static int acp5x_audio_remove(struct platform_device *pdev)
static int __maybe_unused acp5x_pcm_resume(struct device *dev)
{
struct i2s_dev_data *adata;
- u32 val, reg_val, frmt_val;
+ struct i2s_stream_instance *rtd;
+ u32 val;
- reg_val = 0;
- frmt_val = 0;
adata = dev_get_drvdata(dev);
if (adata->play_stream && adata->play_stream->runtime) {
- struct i2s_stream_instance *rtd =
- adata->play_stream->runtime->private_data;
+ rtd = adata->play_stream->runtime->private_data;
config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- reg_val = ACP_HSTDM_ITER;
- frmt_val = ACP_HSTDM_TXFRMT;
- break;
- case I2S_SP_INSTANCE:
- default:
- reg_val = ACP_I2STDM_ITER;
- frmt_val = ACP_I2STDM_TXFRMT;
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_ITER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_TXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_HSTDM_ITER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_ITER);
+ }
+ }
+ if (adata->i2ssp_play_stream && adata->i2ssp_play_stream->runtime) {
+ rtd = adata->i2ssp_play_stream->runtime->private_data;
+ config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_ITER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_TXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_I2STDM_ITER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_ITER);
}
- acp_writel((rtd->xfer_resolution << 3),
- rtd->acp5x_base + reg_val);
}
if (adata->capture_stream && adata->capture_stream->runtime) {
- struct i2s_stream_instance *rtd =
- adata->capture_stream->runtime->private_data;
+ rtd = adata->capture_stream->runtime->private_data;
config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- reg_val = ACP_HSTDM_IRER;
- frmt_val = ACP_HSTDM_RXFRMT;
- break;
- case I2S_SP_INSTANCE:
- default:
- reg_val = ACP_I2STDM_IRER;
- frmt_val = ACP_I2STDM_RXFRMT;
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_IRER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_RXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_HSTDM_IRER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_IRER);
}
- acp_writel((rtd->xfer_resolution << 3),
- rtd->acp5x_base + reg_val);
}
- if (adata->tdm_mode == TDM_ENABLE) {
- acp_writel(adata->tdm_fmt, adata->acp5x_base + frmt_val);
- val = acp_readl(adata->acp5x_base + reg_val);
- acp_writel(val | 0x2, adata->acp5x_base + reg_val);
+ if (adata->i2ssp_capture_stream && adata->i2ssp_capture_stream->runtime) {
+ rtd = adata->i2ssp_capture_stream->runtime->private_data;
+ config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_IRER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_RXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_I2STDM_IRER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_IRER);
+ }
}
acp_writel(1, adata->acp5x_base + ACP_EXTERNAL_INTR_ENB);
return 0;
diff --git a/sound/soc/amd/vangogh/acp5x.h b/sound/soc/amd/vangogh/acp5x.h
index fe5e1fa98974..bd9f1c5684d1 100644
--- a/sound/soc/amd/vangogh/acp5x.h
+++ b/sound/soc/amd/vangogh/acp5x.h
@@ -85,7 +85,7 @@
struct i2s_dev_data {
bool tdm_mode;
bool master_mode;
- unsigned int i2s_irq;
+ int i2s_irq;
u16 i2s_instance;
u32 tdm_fmt;
void __iomem *acp5x_base;
@@ -105,6 +105,8 @@ struct i2s_stream_instance {
dma_addr_t dma_addr;
u64 bytescount;
void __iomem *acp5x_base;
+ u32 lrclk_div;
+ u32 bclk_div;
};
union acp_dma_count {
@@ -191,3 +193,30 @@ static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd,
}
return byte_count.bytescount;
}
+
+static inline void acp5x_set_i2s_clk(struct i2s_dev_data *adata,
+ struct i2s_stream_instance *rtd)
+{
+ union acp_i2stdm_mstrclkgen mclkgen;
+ u32 master_reg;
+
+ switch (rtd->i2s_instance) {
+ case I2S_HS_INSTANCE:
+ master_reg = ACP_I2STDM2_MSTRCLKGEN;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ master_reg = ACP_I2STDM0_MSTRCLKGEN;
+ break;
+ }
+
+ mclkgen.bits.i2stdm_master_mode = 0x1;
+ if (adata->tdm_mode)
+ mclkgen.bits.i2stdm_format_mode = 0x01;
+ else
+ mclkgen.bits.i2stdm_format_mode = 0x00;
+
+ mclkgen.bits.i2stdm_bclk_div_val = rtd->bclk_div;
+ mclkgen.bits.i2stdm_lrclk_div_val = rtd->lrclk_div;
+ acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg);
+}
diff --git a/sound/soc/amd/vangogh/pci-acp5x.c b/sound/soc/amd/vangogh/pci-acp5x.c
index 2b6b9edc36e2..e0df17c88e8e 100644
--- a/sound/soc/amd/vangogh/pci-acp5x.c
+++ b/sound/soc/amd/vangogh/pci-acp5x.c
@@ -92,12 +92,14 @@ static int acp5x_init(void __iomem *acp5x_base)
pr_err("ACP5x power on failed\n");
return ret;
}
+ acp_writel(0x01, acp5x_base + ACP_CONTROL);
/* Reset */
ret = acp5x_reset(acp5x_base);
if (ret) {
pr_err("ACP5x reset failed\n");
return ret;
}
+ acp_writel(0x03, acp5x_base + ACP_CLKMUX_SEL);
acp5x_enable_interrupts(acp5x_base);
return 0;
}
@@ -113,6 +115,8 @@ static int acp5x_deinit(void __iomem *acp5x_base)
pr_err("ACP5x reset failed\n");
return ret;
}
+ acp_writel(0x00, acp5x_base + ACP_CLKMUX_SEL);
+ acp_writel(0x00, acp5x_base + ACP_CONTROL);
return 0;
}
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 9a767f47b89f..f06e6c1a7799 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -12,6 +12,7 @@
#include <sound/pcm_params.h>
#include <linux/io.h>
#include <linux/dmi.h>
+#include <linux/acpi.h>
#include "acp6x.h"
@@ -45,108 +46,126 @@ static struct snd_soc_card acp6x_card = {
static const struct dmi_system_id yc_acp_quirk_table[] = {
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D2"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D3"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D4"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D5"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CF"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CG"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CQ"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CR"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21AW"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21AX"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21BN"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CH"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CJ"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CK"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CL"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D8"),
}
},
{
+ .driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D9"),
@@ -157,18 +176,33 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
static int acp6x_probe(struct platform_device *pdev)
{
+ const struct dmi_system_id *dmi_id;
struct acp6x_pdm *machine = NULL;
struct snd_soc_card *card;
+ struct acpi_device *adev;
int ret;
- const struct dmi_system_id *dmi_id;
+ /* check the parent device's firmware node has _DSD or not */
+ adev = ACPI_COMPANION(pdev->dev.parent);
+ if (adev) {
+ const union acpi_object *obj;
+
+ if (!acpi_dev_get_property(adev, "AcpDmicConnected", ACPI_TYPE_INTEGER, &obj) &&
+ obj->integer.value == 1)
+ platform_set_drvdata(pdev, &acp6x_card);
+ }
+
+ /* check for any DMI overrides */
dmi_id = dmi_first_match(yc_acp_quirk_table);
- if (!dmi_id)
+ if (dmi_id)
+ platform_set_drvdata(pdev, dmi_id->driver_data);
+
+ card = platform_get_drvdata(pdev);
+ if (!card)
return -ENODEV;
- card = &acp6x_card;
+ dev_info(&pdev->dev, "Enabling ACP DMIC support via %s", dmi_id ? "DMI" : "ACPI");
acp6x_card.dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index e604f4ea524f..7e66393e4153 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -318,7 +318,7 @@ static int acp6x_pdm_dai_trigger(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_dai_ops acp6x_pdm_dai_ops = {
+static const struct snd_soc_dai_ops acp6x_pdm_dai_ops = {
.trigger = acp6x_pdm_dai_trigger,
};
diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c
index 7e9a9a9d8ddd..20f7a99783f2 100644
--- a/sound/soc/amd/yc/pci-acp6x.c
+++ b/sound/soc/amd/yc/pci-acp6x.c
@@ -154,9 +154,14 @@ static int snd_acp6x_probe(struct pci_dev *pci,
irqflags = IRQF_SHARED;
/* Yellow Carp device check */
- if (pci->revision != 0x60)
+ switch (pci->revision) {
+ case 0x60:
+ case 0x6f:
+ break;
+ default:
+ dev_err(&pci->dev, "acp6x pci device not found\n");
return -ENODEV;
-
+ }
if (pci_enable_device(pci)) {
dev_err(&pci->dev, "pci_enable_device failed\n");
return -ENODEV;
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 8617793ed955..5d59e00be823 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -42,9 +42,9 @@ config SND_ATMEL_SOC_SSC_DMA
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ARCH_AT91 || COMPILE_TEST
- depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
+ depends on ATMEL_SSC && I2C
select SND_ATMEL_SOC_SSC_PDC
- select SND_SOC_WM8731
+ select SND_SOC_WM8731_I2C
help
Say Y if you want to add support for SoC audio on WM8731-based
AT91sam9g20 evaluation board.
@@ -160,4 +160,20 @@ config SND_MCHP_SOC_SPDIFRX
This S/PDIF RX driver is compliant with IEC-60958 standard and
includes programmable User Data and Channel Status fields.
+
+config SND_MCHP_SOC_PDMC
+ tristate "Microchip ASoC driver for boards using PDMC"
+ depends on OF && (ARCH_AT91 || COMPILE_TEST)
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y or M if you want to add support for Microchip ASoC PDMC driver on the
+ following Microchip platforms:
+ - sama7g5
+
+ The Pulse Density Microphone Controller (PDMC) interfaces up to 4 digital
+ microphones PDM outputs. It generates a single clock line and samples 1 or
+ 2 data lines. The signal path includes an audio grade programmable
+ decimation filter and outputs 24-bit audio words.
+
endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 016188397210..043097a08ea8 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -7,6 +7,7 @@ snd-soc-atmel-i2s-objs := atmel-i2s.o
snd-soc-mchp-i2s-mcc-objs := mchp-i2s-mcc.o
snd-soc-mchp-spdiftx-objs := mchp-spdiftx.o
snd-soc-mchp-spdifrx-objs := mchp-spdifrx.o
+snd-soc-mchp-pdmc-objs := mchp-pdmc.o
# pdc and dma need to both be built-in if any user of
# ssc is built-in.
@@ -21,6 +22,7 @@ obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
obj-$(CONFIG_SND_MCHP_SOC_I2S_MCC) += snd-soc-mchp-i2s-mcc.o
obj-$(CONFIG_SND_MCHP_SOC_SPDIFTX) += snd-soc-mchp-spdiftx.o
obj-$(CONFIG_SND_MCHP_SOC_SPDIFRX) += snd-soc-mchp-spdifrx.o
+obj-$(CONFIG_SND_MCHP_SOC_PDMC) += snd-soc-mchp-pdmc.o
# AT91 Machine Support
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index a9f9f449c48c..74b7b2611aa7 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -458,7 +458,6 @@ static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = {
.num_controls = ARRAY_SIZE(atmel_classd_snd_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
- .endianness = 1,
};
/* ASoC sound card */
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index 42117de299e7..ea34efac2fff 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -481,7 +481,6 @@ static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = {
.num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls),
.idle_bias_on = 1,
.use_pmdown_time = 1,
- .endianness = 1,
};
/* ASoC sound card */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 26e2bc690d86..c1dea8d62416 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -280,7 +280,10 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
/* Enable PMC peripheral clock for this SSC */
pr_debug("atmel_ssc_dai: Starting clock\n");
- clk_enable(ssc_p->ssc->clk);
+ ret = clk_enable(ssc_p->ssc->clk);
+ if (ret)
+ return ret;
+
ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
/* Reset the SSC unless initialized to keep it in a clean state */
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
new file mode 100644
index 000000000000..a3856c73e221
--- /dev/null
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -0,0 +1,1084 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for Microchip Pulse Density Microphone Controller (PDMC) interfaces
+//
+// Copyright (C) 2019-2022 Microchip Technology Inc. and its subsidiaries
+//
+// Author: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
+
+#include <dt-bindings/sound/microchip,pdmc.h>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+/*
+ * ---- PDMC Register map ----
+ */
+#define MCHP_PDMC_CR 0x00 /* Control Register */
+#define MCHP_PDMC_MR 0x04 /* Mode Register */
+#define MCHP_PDMC_CFGR 0x08 /* Configuration Register */
+#define MCHP_PDMC_RHR 0x0C /* Receive Holding Register */
+#define MCHP_PDMC_IER 0x14 /* Interrupt Enable Register */
+#define MCHP_PDMC_IDR 0x18 /* Interrupt Disable Register */
+#define MCHP_PDMC_IMR 0x1C /* Interrupt Mask Register */
+#define MCHP_PDMC_ISR 0x20 /* Interrupt Status Register */
+#define MCHP_PDMC_VER 0x50 /* Version Register */
+
+/*
+ * ---- Control Register (Write-only) ----
+ */
+#define MCHP_PDMC_CR_SWRST BIT(0) /* Software Reset */
+
+/*
+ * ---- Mode Register (Read/Write) ----
+ */
+#define MCHP_PDMC_MR_PDMCEN_MASK GENMASK(3, 0)
+#define MCHP_PDMC_MR_PDMCEN(ch) (BIT(ch) & MCHP_PDMC_MR_PDMCEN_MASK)
+
+#define MCHP_PDMC_MR_OSR_MASK GENMASK(17, 16)
+#define MCHP_PDMC_MR_OSR64 (1 << 16)
+#define MCHP_PDMC_MR_OSR128 (2 << 16)
+#define MCHP_PDMC_MR_OSR256 (3 << 16)
+
+#define MCHP_PDMC_MR_SINCORDER_MASK GENMASK(23, 20)
+#define MCHP_PDMC_MR_SINCORDER(order) (((order) << 20) & \
+ MCHP_PDMC_MR_SINCORDER_MASK)
+
+#define MCHP_PDMC_MR_SINC_OSR_MASK GENMASK(27, 24)
+#define MCHP_PDMC_MR_SINC_OSR_DIS (0 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_8 (1 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_16 (2 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_32 (3 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_64 (4 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_128 (5 << 24)
+#define MCHP_PDMC_MR_SINC_OSR_256 (6 << 24)
+
+#define MCHP_PDMC_MR_CHUNK_MASK GENMASK(31, 28)
+#define MCHP_PDMC_MR_CHUNK(chunk) (((chunk) << 28) & \
+ MCHP_PDMC_MR_CHUNK_MASK)
+
+/*
+ * ---- Configuration Register (Read/Write) ----
+ */
+#define MCHP_PDMC_CFGR_BSSEL_MASK (BIT(0) | BIT(2) | BIT(4) | BIT(6))
+#define MCHP_PDMC_CFGR_BSSEL(ch) BIT((ch) * 2)
+
+#define MCHP_PDMC_CFGR_PDMSEL_MASK (BIT(16) | BIT(18) | BIT(20) | BIT(22))
+#define MCHP_PDMC_CFGR_PDMSEL(ch) BIT((ch) * 2 + 16)
+
+/*
+ * ---- Interrupt Enable/Disable/Mask/Status Registers ----
+ */
+#define MCHP_PDMC_IR_RXRDY BIT(0)
+#define MCHP_PDMC_IR_RXEMPTY BIT(1)
+#define MCHP_PDMC_IR_RXFULL BIT(2)
+#define MCHP_PDMC_IR_RXCHUNK BIT(3)
+#define MCHP_PDMC_IR_RXUDR BIT(4)
+#define MCHP_PDMC_IR_RXOVR BIT(5)
+
+/*
+ * ---- Version Register (Read-only) ----
+ */
+#define MCHP_PDMC_VER_VERSION GENMASK(11, 0)
+
+#define MCHP_PDMC_MAX_CHANNELS 4
+#define MCHP_PDMC_DS_NO 2
+#define MCHP_PDMC_EDGE_NO 2
+
+struct mic_map {
+ int ds_pos;
+ int clk_edge;
+};
+
+struct mchp_pdmc_chmap {
+ struct snd_pcm_chmap_elem *chmap;
+ struct mchp_pdmc *dd;
+ struct snd_pcm *pcm;
+ struct snd_kcontrol *kctl;
+};
+
+struct mchp_pdmc {
+ struct mic_map channel_mic_map[MCHP_PDMC_MAX_CHANNELS];
+ struct device *dev;
+ struct snd_dmaengine_dai_dma_data addr;
+ struct regmap *regmap;
+ struct clk *pclk;
+ struct clk *gclk;
+ u32 pdmcen;
+ int mic_no;
+ int sinc_order;
+ bool audio_filter_en;
+ u8 gclk_enabled:1;
+};
+
+static const char *const mchp_pdmc_sinc_filter_order_text[] = {
+ "1", "2", "3", "4", "5"
+};
+
+static const unsigned int mchp_pdmc_sinc_filter_order_values[] = {
+ 1, 2, 3, 4, 5,
+};
+
+static const struct soc_enum mchp_pdmc_sinc_filter_order_enum = {
+ .items = ARRAY_SIZE(mchp_pdmc_sinc_filter_order_text),
+ .texts = mchp_pdmc_sinc_filter_order_text,
+ .values = mchp_pdmc_sinc_filter_order_values,
+};
+
+static int mchp_pdmc_sinc_order_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int item;
+
+ item = snd_soc_enum_val_to_item(e, dd->sinc_order);
+ uvalue->value.enumerated.item[0] = item;
+
+ return 0;
+}
+
+static int mchp_pdmc_sinc_order_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = uvalue->value.enumerated.item;
+ unsigned int val;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ if (val == dd->sinc_order)
+ return 0;
+
+ dd->sinc_order = val;
+
+ return 1;
+}
+
+static int mchp_pdmc_af_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
+
+ uvalue->value.integer.value[0] = !!dd->audio_filter_en;
+
+ return 0;
+}
+
+static int mchp_pdmc_af_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
+ bool af = uvalue->value.integer.value[0] ? true : false;
+
+ if (dd->audio_filter_en == af)
+ return 0;
+
+ dd->audio_filter_en = af;
+
+ return 1;
+}
+
+static int mchp_pdmc_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ struct mchp_pdmc_chmap *info = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = info->dd->mic_no;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_RR; /* maxmimum 4 channels */
+ return 0;
+}
+
+static inline struct snd_pcm_substream *
+mchp_pdmc_chmap_substream(struct mchp_pdmc_chmap *info, unsigned int idx)
+{
+ struct snd_pcm_substream *s;
+
+ for (s = info->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; s; s = s->next)
+ if (s->number == idx)
+ return s;
+ return NULL;
+}
+
+static struct snd_pcm_chmap_elem *mchp_pdmc_chmap_get(struct snd_pcm_substream *substream,
+ struct mchp_pdmc_chmap *ch_info)
+{
+ struct snd_pcm_chmap_elem *map;
+
+ for (map = ch_info->chmap; map->channels; map++) {
+ if (map->channels == substream->runtime->channels)
+ return map;
+ }
+ return NULL;
+}
+
+static int mchp_pdmc_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct mchp_pdmc_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = info->dd;
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ const struct snd_pcm_chmap_elem *map;
+ int i;
+ u32 cfgr_val = 0;
+
+ if (!info->chmap)
+ return -EINVAL;
+ substream = mchp_pdmc_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0, sizeof(long) * info->dd->mic_no);
+ if (!substream->runtime)
+ return 0; /* no channels set */
+
+ map = mchp_pdmc_chmap_get(substream, info);
+ if (!map)
+ return -EINVAL;
+
+ for (i = 0; i < map->channels; i++) {
+ int map_idx = map->channels == 1 ? map->map[i] - SNDRV_CHMAP_MONO :
+ map->map[i] - SNDRV_CHMAP_FL;
+
+ /* make sure the reported channel map is the real one, so write the map */
+ if (dd->channel_mic_map[map_idx].ds_pos)
+ cfgr_val |= MCHP_PDMC_CFGR_PDMSEL(i);
+ if (dd->channel_mic_map[map_idx].clk_edge)
+ cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i);
+
+ ucontrol->value.integer.value[i] = map->map[i];
+ }
+
+ regmap_write(dd->regmap, MCHP_PDMC_CFGR, cfgr_val);
+
+ return 0;
+}
+
+static int mchp_pdmc_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct mchp_pdmc_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct mchp_pdmc *dd = info->dd;
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_chmap_elem *map;
+ u32 cfgr_val = 0;
+ int i;
+
+ if (!info->chmap)
+ return -EINVAL;
+ substream = mchp_pdmc_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+
+ map = mchp_pdmc_chmap_get(substream, info);
+ if (!map)
+ return -EINVAL;
+
+ for (i = 0; i < map->channels; i++) {
+ int map_idx;
+
+ map->map[i] = ucontrol->value.integer.value[i];
+ map_idx = map->channels == 1 ? map->map[i] - SNDRV_CHMAP_MONO :
+ map->map[i] - SNDRV_CHMAP_FL;
+
+ /* configure IP for the desired channel map */
+ if (dd->channel_mic_map[map_idx].ds_pos)
+ cfgr_val |= MCHP_PDMC_CFGR_PDMSEL(i);
+ if (dd->channel_mic_map[map_idx].clk_edge)
+ cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i);
+ }
+
+ regmap_write(dd->regmap, MCHP_PDMC_CFGR, cfgr_val);
+
+ return 0;
+}
+
+static void mchp_pdmc_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct mchp_pdmc_chmap *info = snd_kcontrol_chip(kcontrol);
+
+ info->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].chmap_kctl = NULL;
+ kfree(info);
+}
+
+static int mchp_pdmc_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct mchp_pdmc_chmap *info = snd_kcontrol_chip(kcontrol);
+ const struct snd_pcm_chmap_elem *map;
+ unsigned int __user *dst;
+ int c, count = 0;
+
+ if (!info->chmap)
+ return -EINVAL;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+ return -EFAULT;
+ size -= 8;
+ dst = tlv + 2;
+ for (map = info->chmap; map->channels; map++) {
+ int chs_bytes = map->channels * 4;
+
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
+ put_user(chs_bytes, dst + 1))
+ return -EFAULT;
+ dst += 2;
+ size -= 8;
+ count += 8;
+ if (size < chs_bytes)
+ return -ENOMEM;
+ size -= chs_bytes;
+ count += chs_bytes;
+ for (c = 0; c < map->channels; c++) {
+ if (put_user(map->map[c], dst))
+ return -EFAULT;
+ dst++;
+ }
+ }
+ if (put_user(count, tlv + 1))
+ return -EFAULT;
+ return 0;
+}
+
+static const struct snd_kcontrol_new mchp_pdmc_snd_controls[] = {
+ SOC_SINGLE_BOOL_EXT("Audio Filter", 0, &mchp_pdmc_af_get, &mchp_pdmc_af_put),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SINC Filter Order",
+ .info = snd_soc_info_enum_double,
+ .get = mchp_pdmc_sinc_order_get,
+ .put = mchp_pdmc_sinc_order_put,
+ .private_value = (unsigned long)&mchp_pdmc_sinc_filter_order_enum,
+ },
+};
+
+static int mchp_pdmc_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ return snd_soc_add_component_controls(component, mchp_pdmc_snd_controls,
+ ARRAY_SIZE(mchp_pdmc_snd_controls));
+}
+
+static int mchp_pdmc_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ int i;
+
+ /* remove controls that can't be changed at runtime */
+ for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) {
+ const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i];
+ struct snd_ctl_elem_id id;
+ struct snd_kcontrol *kctl;
+ int err;
+
+ if (component->name_prefix)
+ snprintf(id.name, sizeof(id.name), "%s %s", component->name_prefix,
+ control->name);
+ else
+ strscpy(id.name, control->name, sizeof(id.name));
+
+ id.numid = 0;
+ id.iface = control->iface;
+ id.device = control->device;
+ id.subdevice = control->subdevice;
+ id.index = control->index;
+ kctl = snd_ctl_find_id(component->card->snd_card, &id);
+ if (!kctl) {
+ dev_err(component->dev, "Failed to find %s\n", control->name);
+ continue;
+ }
+ err = snd_ctl_remove(component->card->snd_card, kctl);
+ if (err < 0) {
+ dev_err(component->dev, "%d: Failed to remove %s\n", err,
+ control->name);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver mchp_pdmc_dai_component = {
+ .name = "mchp-pdmc",
+ .controls = mchp_pdmc_snd_controls,
+ .num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls),
+ .open = &mchp_pdmc_open,
+ .close = &mchp_pdmc_close,
+};
+
+static const unsigned int mchp_pdmc_1mic[] = {1};
+static const unsigned int mchp_pdmc_2mic[] = {1, 2};
+static const unsigned int mchp_pdmc_3mic[] = {1, 2, 3};
+static const unsigned int mchp_pdmc_4mic[] = {1, 2, 3, 4};
+
+static const struct snd_pcm_hw_constraint_list mchp_pdmc_chan_constr[] = {
+ {
+ .list = mchp_pdmc_1mic,
+ .count = ARRAY_SIZE(mchp_pdmc_1mic),
+ },
+ {
+ .list = mchp_pdmc_2mic,
+ .count = ARRAY_SIZE(mchp_pdmc_2mic),
+ },
+ {
+ .list = mchp_pdmc_3mic,
+ .count = ARRAY_SIZE(mchp_pdmc_3mic),
+ },
+ {
+ .list = mchp_pdmc_4mic,
+ .count = ARRAY_SIZE(mchp_pdmc_4mic),
+ },
+};
+
+static int mchp_pdmc_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(dd->pclk);
+ if (ret) {
+ dev_err(dd->dev, "failed to enable the peripheral clock: %d\n", ret);
+ return ret;
+ }
+
+ regmap_write(dd->regmap, MCHP_PDMC_CR, MCHP_PDMC_CR_SWRST);
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &mchp_pdmc_chan_constr[dd->mic_no - 1]);
+
+ return 0;
+}
+
+static void mchp_pdmc_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(dd->pclk);
+}
+
+static int mchp_pdmc_dai_probe(struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, NULL, &dd->addr);
+
+ return 0;
+}
+
+static int mchp_pdmc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ unsigned int fmt_master = fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ unsigned int fmt_format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+ /* IP needs to be bitclock master */
+ if (fmt_master != SND_SOC_DAIFMT_CBS_CFS &&
+ fmt_master != SND_SOC_DAIFMT_CBS_CFM)
+ return -EINVAL;
+
+ /* IP supports only PDM interface */
+ if (fmt_format != SND_SOC_DAIFMT_PDM)
+ return -EINVAL;
+
+ return 0;
+}
+
+static u32 mchp_pdmc_mr_set_osr(int audio_filter_en, unsigned int osr)
+{
+ if (audio_filter_en) {
+ switch (osr) {
+ case 64:
+ return MCHP_PDMC_MR_OSR64;
+ case 128:
+ return MCHP_PDMC_MR_OSR128;
+ case 256:
+ return MCHP_PDMC_MR_OSR256;
+ }
+ } else {
+ switch (osr) {
+ case 8:
+ return MCHP_PDMC_MR_SINC_OSR_8;
+ case 16:
+ return MCHP_PDMC_MR_SINC_OSR_16;
+ case 32:
+ return MCHP_PDMC_MR_SINC_OSR_32;
+ case 64:
+ return MCHP_PDMC_MR_SINC_OSR_64;
+ case 128:
+ return MCHP_PDMC_MR_SINC_OSR_128;
+ case 256:
+ return MCHP_PDMC_MR_SINC_OSR_256;
+ }
+ }
+ return 0;
+}
+
+static inline int mchp_pdmc_period_to_maxburst(int period_size)
+{
+ if (!(period_size % 8))
+ return 8;
+ if (!(period_size % 4))
+ return 4;
+ if (!(period_size % 2))
+ return 2;
+ return 1;
+}
+
+static struct snd_pcm_chmap_elem mchp_pdmc_std_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 3,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { }
+};
+
+static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ unsigned long gclk_rate = 0;
+ unsigned long best_diff_rate = ~0UL;
+ unsigned int channels = params_channels(params);
+ unsigned int osr = 0, osr_start;
+ unsigned int fs = params_rate(params);
+ u32 mr_val = 0;
+ u32 cfgr_val = 0;
+ int i;
+ int ret;
+
+ dev_dbg(comp->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
+ __func__, params_rate(params), params_format(params),
+ params_width(params), params_channels(params));
+
+ if (channels > dd->mic_no) {
+ dev_err(comp->dev, "more channels %u than microphones %d\n",
+ channels, dd->mic_no);
+ return -EINVAL;
+ }
+
+ dd->pdmcen = 0;
+ for (i = 0; i < channels; i++) {
+ dd->pdmcen |= MCHP_PDMC_MR_PDMCEN(i);
+ if (dd->channel_mic_map[i].ds_pos)
+ cfgr_val |= MCHP_PDMC_CFGR_PDMSEL(i);
+ if (dd->channel_mic_map[i].clk_edge)
+ cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i);
+ }
+
+ if (dd->gclk_enabled) {
+ clk_disable_unprepare(dd->gclk);
+ dd->gclk_enabled = 0;
+ }
+
+ for (osr_start = dd->audio_filter_en ? 64 : 8;
+ osr_start <= 256 && best_diff_rate; osr_start *= 2) {
+ long round_rate;
+ unsigned long diff_rate;
+
+ round_rate = clk_round_rate(dd->gclk,
+ (unsigned long)fs * 16 * osr_start);
+ if (round_rate < 0)
+ continue;
+ diff_rate = abs((fs * 16 * osr_start) - round_rate);
+ if (diff_rate < best_diff_rate) {
+ best_diff_rate = diff_rate;
+ osr = osr_start;
+ gclk_rate = fs * 16 * osr;
+ }
+ }
+ if (!gclk_rate) {
+ dev_err(comp->dev, "invalid sampling rate: %u\n", fs);
+ return -EINVAL;
+ }
+
+ /* set the rate */
+ ret = clk_set_rate(dd->gclk, gclk_rate);
+ if (ret) {
+ dev_err(comp->dev, "unable to set rate %lu to GCLK: %d\n",
+ gclk_rate, ret);
+ return ret;
+ }
+
+ mr_val |= mchp_pdmc_mr_set_osr(dd->audio_filter_en, osr);
+
+ mr_val |= MCHP_PDMC_MR_SINCORDER(dd->sinc_order);
+
+ dd->addr.maxburst = mchp_pdmc_period_to_maxburst(snd_pcm_lib_period_bytes(substream));
+ mr_val |= MCHP_PDMC_MR_CHUNK(dd->addr.maxburst);
+ dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst);
+
+ clk_prepare_enable(dd->gclk);
+ dd->gclk_enabled = 1;
+
+ snd_soc_component_update_bits(comp, MCHP_PDMC_MR,
+ MCHP_PDMC_MR_OSR_MASK |
+ MCHP_PDMC_MR_SINCORDER_MASK |
+ MCHP_PDMC_MR_SINC_OSR_MASK |
+ MCHP_PDMC_MR_CHUNK_MASK, mr_val);
+
+ snd_soc_component_write(comp, MCHP_PDMC_CFGR, cfgr_val);
+
+ return 0;
+}
+
+static int mchp_pdmc_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+
+ if (dd->gclk_enabled) {
+ clk_disable_unprepare(dd->gclk);
+ dd->gclk_enabled = 0;
+ }
+
+ return 0;
+}
+
+static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *cpu = dai->component;
+#ifdef DEBUG
+ u32 val;
+#endif
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /* Enable overrun and underrun error interrupts */
+ regmap_write(dd->regmap, MCHP_PDMC_IER,
+ MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR);
+ snd_soc_component_update_bits(cpu, MCHP_PDMC_MR,
+ MCHP_PDMC_MR_PDMCEN_MASK,
+ dd->pdmcen);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /* Disable overrun and underrun error interrupts */
+ regmap_write(dd->regmap, MCHP_PDMC_IDR,
+ MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR);
+ snd_soc_component_update_bits(cpu, MCHP_PDMC_MR,
+ MCHP_PDMC_MR_PDMCEN_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+#ifdef DEBUG
+ regmap_read(dd->regmap, MCHP_PDMC_MR, &val);
+ dev_dbg(dd->dev, "MR (0x%02x): 0x%08x\n", MCHP_PDMC_MR, val);
+ regmap_read(dd->regmap, MCHP_PDMC_CFGR, &val);
+ dev_dbg(dd->dev, "CFGR (0x%02x): 0x%08x\n", MCHP_PDMC_CFGR, val);
+ regmap_read(dd->regmap, MCHP_PDMC_IMR, &val);
+ dev_dbg(dd->dev, "IMR (0x%02x): 0x%08x\n", MCHP_PDMC_IMR, val);
+#endif
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
+ .set_fmt = mchp_pdmc_set_fmt,
+ .startup = mchp_pdmc_startup,
+ .shutdown = mchp_pdmc_shutdown,
+ .hw_params = mchp_pdmc_hw_params,
+ .hw_free = mchp_pdmc_hw_free,
+ .trigger = mchp_pdmc_trigger,
+};
+
+static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd)
+{
+ struct mchp_pdmc_chmap *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = mchp_pdmc_chmap_ctl_info,
+ .get = mchp_pdmc_chmap_ctl_get,
+ .put = mchp_pdmc_chmap_ctl_put,
+ .tlv.c = mchp_pdmc_chmap_ctl_tlv,
+ };
+ int err;
+
+ if (WARN_ON(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].chmap_kctl))
+ return -EBUSY;
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->dd = dd;
+ info->chmap = mchp_pdmc_std_chmaps;
+ knew.name = "Capture Channel Map";
+ knew.device = pcm->device;
+ knew.count = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = mchp_pdmc_chmap_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0)
+ return err;
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].chmap_kctl = info->kctl;
+ return 0;
+}
+
+static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai)
+{
+ struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = mchp_pdmc_add_chmap_ctls(rtd->pcm, dd);
+ if (ret < 0) {
+ dev_err(dd->dev, "failed to add channel map controls: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver mchp_pdmc_dai = {
+ .probe = mchp_pdmc_dai_probe,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &mchp_pdmc_dai_ops,
+ .pcm_new = &mchp_pdmc_pcm_new,
+};
+
+/* PDMC interrupt handler */
+static irqreturn_t mchp_pdmc_interrupt(int irq, void *dev_id)
+{
+ struct mchp_pdmc *dd = (struct mchp_pdmc *)dev_id;
+ u32 isr, msr, pending;
+ irqreturn_t ret = IRQ_NONE;
+
+ regmap_read(dd->regmap, MCHP_PDMC_ISR, &isr);
+ regmap_read(dd->regmap, MCHP_PDMC_IMR, &msr);
+
+ pending = isr & msr;
+ dev_dbg(dd->dev, "ISR (0x%02x): 0x%08x, IMR (0x%02x): 0x%08x, pending: 0x%08x\n",
+ MCHP_PDMC_ISR, isr, MCHP_PDMC_IMR, msr, pending);
+ if (!pending)
+ return IRQ_NONE;
+
+ if (pending & MCHP_PDMC_IR_RXUDR) {
+ dev_warn(dd->dev, "underrun detected\n");
+ regmap_write(dd->regmap, MCHP_PDMC_IDR, MCHP_PDMC_IR_RXUDR);
+ ret = IRQ_HANDLED;
+ }
+ if (pending & MCHP_PDMC_IR_RXOVR) {
+ dev_warn(dd->dev, "overrun detected\n");
+ regmap_write(dd->regmap, MCHP_PDMC_IDR, MCHP_PDMC_IR_RXOVR);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+/* regmap configuration */
+static bool mchp_pdmc_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MCHP_PDMC_MR:
+ case MCHP_PDMC_CFGR:
+ case MCHP_PDMC_IMR:
+ case MCHP_PDMC_ISR:
+ case MCHP_PDMC_VER:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool mchp_pdmc_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MCHP_PDMC_CR:
+ case MCHP_PDMC_MR:
+ case MCHP_PDMC_CFGR:
+ case MCHP_PDMC_IER:
+ case MCHP_PDMC_IDR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool mchp_pdmc_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MCHP_PDMC_RHR:
+ case MCHP_PDMC_ISR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config mchp_pdmc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = MCHP_PDMC_VER,
+ .readable_reg = mchp_pdmc_readable_reg,
+ .writeable_reg = mchp_pdmc_writeable_reg,
+ .precious_reg = mchp_pdmc_precious_reg,
+};
+
+static int mchp_pdmc_dt_init(struct mchp_pdmc *dd)
+{
+ struct device_node *np = dd->dev->of_node;
+ bool mic_ch[MCHP_PDMC_DS_NO][MCHP_PDMC_EDGE_NO] = {0};
+ int i;
+ int ret;
+
+ if (!np) {
+ dev_err(dd->dev, "device node not found\n");
+ return -EINVAL;
+ }
+
+ dd->mic_no = of_property_count_u32_elems(np, "microchip,mic-pos");
+ if (dd->mic_no < 0) {
+ dev_err(dd->dev, "failed to get microchip,mic-pos: %d",
+ dd->mic_no);
+ return dd->mic_no;
+ }
+ if (!dd->mic_no || dd->mic_no % 2 ||
+ dd->mic_no / 2 > MCHP_PDMC_MAX_CHANNELS) {
+ dev_err(dd->dev, "invalid array length for microchip,mic-pos: %d",
+ dd->mic_no);
+ return -EINVAL;
+ }
+
+ dd->mic_no /= 2;
+
+ dev_info(dd->dev, "%d PDM microphones declared\n", dd->mic_no);
+
+ /*
+ * by default, we consider the order of microphones in
+ * microchip,mic-pos to be the same with the channel mapping;
+ * 1st microphone channel 0, 2nd microphone channel 1, etc.
+ */
+ for (i = 0; i < dd->mic_no; i++) {
+ int ds;
+ int edge;
+
+ ret = of_property_read_u32_index(np, "microchip,mic-pos", i * 2,
+ &ds);
+ if (ret) {
+ dev_err(dd->dev,
+ "failed to get value no %d value from microchip,mic-pos: %d",
+ i * 2, ret);
+ return ret;
+ }
+ if (ds >= MCHP_PDMC_DS_NO) {
+ dev_err(dd->dev,
+ "invalid DS index in microchip,mic-pos array: %d",
+ ds);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(np, "microchip,mic-pos", i * 2 + 1,
+ &edge);
+ if (ret) {
+ dev_err(dd->dev,
+ "failed to get value no %d value from microchip,mic-pos: %d",
+ i * 2 + 1, ret);
+ return ret;
+ }
+
+ if (edge != MCHP_PDMC_CLK_POSITIVE &&
+ edge != MCHP_PDMC_CLK_NEGATIVE) {
+ dev_err(dd->dev,
+ "invalid edge in microchip,mic-pos array: %d", edge);
+ return -EINVAL;
+ }
+ if (mic_ch[ds][edge]) {
+ dev_err(dd->dev,
+ "duplicated mic (DS %d, edge %d) in microchip,mic-pos array",
+ ds, edge);
+ return -EINVAL;
+ }
+ mic_ch[ds][edge] = true;
+ dd->channel_mic_map[i].ds_pos = ds;
+ dd->channel_mic_map[i].clk_edge = edge;
+ }
+
+ return 0;
+}
+
+/* used to clean the channel index found on RHR's MSB */
+static int mchp_pdmc_process(struct snd_pcm_substream *substream,
+ int channel, unsigned long hwoff,
+ void *buf, unsigned long bytes)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u8 *dma_ptr = runtime->dma_area + hwoff +
+ channel * (runtime->dma_bytes / runtime->channels);
+ u8 *dma_ptr_end = dma_ptr + bytes;
+ unsigned int sample_size = samples_to_bytes(runtime, 1);
+
+ for (; dma_ptr < dma_ptr_end; dma_ptr += sample_size)
+ *dma_ptr = 0;
+
+ return 0;
+}
+
+static struct snd_dmaengine_pcm_config mchp_pdmc_config = {
+ .process = mchp_pdmc_process,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+};
+
+static int mchp_pdmc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mchp_pdmc *dd;
+ struct resource *res;
+ void __iomem *io_base;
+ u32 version;
+ int irq;
+ int ret;
+
+ dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+
+ dd->dev = &pdev->dev;
+ ret = mchp_pdmc_dt_init(dd);
+ if (ret < 0)
+ return ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ dd->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(dd->pclk)) {
+ ret = PTR_ERR(dd->pclk);
+ dev_err(dev, "failed to get peripheral clock: %d\n", ret);
+ return ret;
+ }
+
+ dd->gclk = devm_clk_get(dev, "gclk");
+ if (IS_ERR(dd->gclk)) {
+ ret = PTR_ERR(dd->gclk);
+ dev_err(dev, "failed to get GCK: %d\n", ret);
+ return ret;
+ }
+
+ io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(io_base)) {
+ ret = PTR_ERR(io_base);
+ dev_err(dev, "failed to remap register memory: %d\n", ret);
+ return ret;
+ }
+
+ dd->regmap = devm_regmap_init_mmio(dev, io_base,
+ &mchp_pdmc_regmap_config);
+ if (IS_ERR(dd->regmap)) {
+ ret = PTR_ERR(dd->regmap);
+ dev_err(dev, "failed to init register map: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_irq(dev, irq, mchp_pdmc_interrupt, 0,
+ dev_name(&pdev->dev), (void *)dd);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ irq, ret);
+ return ret;
+ }
+
+ /* by default audio filter is enabled and the SINC Filter order
+ * will be set to the recommended value, 3
+ */
+ dd->audio_filter_en = true;
+ dd->sinc_order = 3;
+
+ dd->addr.addr = (dma_addr_t)res->start + MCHP_PDMC_RHR;
+ platform_set_drvdata(pdev, dd);
+
+ /* register platform */
+ ret = devm_snd_dmaengine_pcm_register(dev, &mchp_pdmc_config, 0);
+ if (ret) {
+ dev_err(dev, "could not register platform: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(dev, &mchp_pdmc_dai_component,
+ &mchp_pdmc_dai, 1);
+ if (ret) {
+ dev_err(dev, "could not register CPU DAI: %d\n", ret);
+ return ret;
+ }
+
+ /* print IP version */
+ regmap_read(dd->regmap, MCHP_PDMC_VER, &version);
+ dev_info(dd->dev, "hw version: %#lx\n",
+ version & MCHP_PDMC_VER_VERSION);
+
+ return 0;
+}
+
+static const struct of_device_id mchp_pdmc_of_match[] = {
+ {
+ .compatible = "microchip,sama7g5-pdmc",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, mchp_pdmc_of_match);
+
+static struct platform_driver mchp_pdmc_driver = {
+ .driver = {
+ .name = "mchp-pdmc",
+ .of_match_table = of_match_ptr(mchp_pdmc_of_match),
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mchp_pdmc_probe,
+};
+module_platform_driver(mchp_pdmc_driver);
+
+MODULE_DESCRIPTION("Microchip PDMC driver under ALSA SoC architecture");
+MODULE_AUTHOR("Codrin Ciubotariu <codrin.ciubotariu@microchip.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c
index bcd4f3e4fb0f..5fc968483f2c 100644
--- a/sound/soc/atmel/mchp-spdifrx.c
+++ b/sound/soc/atmel/mchp-spdifrx.c
@@ -920,7 +920,7 @@ static int mchp_spdifrx_probe(struct platform_device *pdev)
err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (err) {
- dev_err(&pdev->dev, "failed to register PMC: %d\n", err);
+ dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
return err;
}
diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c
index f9331f7e80fe..ce46d8a0b7e4 100644
--- a/sound/soc/atmel/mikroe-proto.c
+++ b/sound/soc/atmel/mikroe-proto.c
@@ -115,7 +115,8 @@ static int snd_proto_probe(struct platform_device *pdev)
cpu_np = of_parse_phandle(np, "i2s-controller", 0);
if (!cpu_np) {
dev_err(&pdev->dev, "i2s-controller missing\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_codec_node;
}
dai->cpus->of_node = cpu_np;
dai->platforms->of_node = cpu_np;
@@ -125,7 +126,8 @@ static int snd_proto_probe(struct platform_device *pdev)
&bitclkmaster, &framemaster);
if (bitclkmaster != framemaster) {
dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_cpu_node;
}
if (bitclkmaster) {
if (codec_np == bitclkmaster)
@@ -136,18 +138,20 @@ static int snd_proto_probe(struct platform_device *pdev)
dai_fmt |= snd_soc_daifmt_parse_clock_provider_as_flag(np, NULL);
}
- of_node_put(bitclkmaster);
- of_node_put(framemaster);
- dai->dai_fmt = dai_fmt;
-
- of_node_put(codec_np);
- of_node_put(cpu_np);
+ dai->dai_fmt = dai_fmt;
ret = snd_soc_register_card(&snd_proto);
- if (ret && ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "snd_soc_register_card() failed: %d\n", ret);
+ if (ret)
+ dev_err_probe(&pdev->dev, ret,
+ "snd_soc_register_card() failed\n");
+
+put_cpu_node:
+ of_node_put(bitclkmaster);
+ of_node_put(framemaster);
+ of_node_put(cpu_np);
+put_codec_node:
+ of_node_put(codec_np);
return ret;
}
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 915da92e1ec8..4d25fb61c652 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -46,35 +46,6 @@
*/
#undef ENABLE_MIC_INPUT
-static struct clk *mclk;
-
-static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level)
-{
- static int mclk_on;
- int ret = 0;
-
- switch (level) {
- case SND_SOC_BIAS_ON:
- case SND_SOC_BIAS_PREPARE:
- if (!mclk_on)
- ret = clk_enable(mclk);
- if (ret == 0)
- mclk_on = 1;
- break;
-
- case SND_SOC_BIAS_OFF:
- case SND_SOC_BIAS_STANDBY:
- if (mclk_on)
- clk_disable(mclk);
- mclk_on = 0;
- break;
- }
-
- return ret;
-}
-
static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
@@ -135,7 +106,6 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.owner = THIS_MODULE,
.dai_link = &at91sam9g20ek_dai,
.num_links = 1,
- .set_bias_level = at91sam9g20ek_set_bias_level,
.dapm_widgets = at91sam9g20ek_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
@@ -148,7 +118,6 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *codec_np, *cpu_np;
- struct clk *pllb;
struct snd_soc_card *card = &snd_soc_at91sam9g20ek;
int ret;
@@ -158,35 +127,10 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
ret = atmel_ssc_set_audio(0);
if (ret) {
- dev_err(&pdev->dev, "ssc channel is not valid\n");
- return -EINVAL;
- }
-
- /*
- * Codec MCLK is supplied by PCK0 - set it up.
- */
- mclk = clk_get(NULL, "pck0");
- if (IS_ERR(mclk)) {
- dev_err(&pdev->dev, "Failed to get MCLK\n");
- ret = PTR_ERR(mclk);
- goto err;
- }
-
- pllb = clk_get(NULL, "pllb");
- if (IS_ERR(pllb)) {
- dev_err(&pdev->dev, "Failed to get PLLB\n");
- ret = PTR_ERR(pllb);
- goto err_mclk;
- }
- ret = clk_set_parent(mclk, pllb);
- clk_put(pllb);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to set MCLK parent\n");
- goto err_mclk;
+ dev_err(&pdev->dev, "ssc channel is not valid: %d\n", ret);
+ return ret;
}
- clk_set_rate(mclk, MCLK_RATE);
-
card->dev = &pdev->dev;
/* Parse device node info */
@@ -204,7 +148,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
if (!codec_np) {
dev_err(&pdev->dev, "codec info missing\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
at91sam9g20ek_dai.codecs->of_node = codec_np;
@@ -214,7 +159,9 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
if (!cpu_np) {
dev_err(&pdev->dev, "dai and pcm info missing\n");
- return -EINVAL;
+ of_node_put(codec_np);
+ ret = -EINVAL;
+ goto err;
}
at91sam9g20ek_dai.cpus->of_node = cpu_np;
at91sam9g20ek_dai.platforms->of_node = cpu_np;
@@ -224,14 +171,13 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
ret = snd_soc_register_card(card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card() failed\n");
+ dev_err_probe(&pdev->dev, ret,
+ "snd_soc_register_card() failed: %d\n", ret);
+ goto err;
}
- return ret;
+ return 0;
-err_mclk:
- clk_put(mclk);
- mclk = NULL;
err:
atmel_ssc_put_audio(0);
return ret;
@@ -241,8 +187,6 @@ static int at91sam9g20ek_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- clk_disable(mclk);
- mclk = NULL;
snd_soc_unregister_card(card);
atmel_ssc_put_audio(0);
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
index 7c45dc4f8c1b..99310e40e7a6 100644
--- a/sound/soc/atmel/sam9x5_wm8731.c
+++ b/sound/soc/atmel/sam9x5_wm8731.c
@@ -142,7 +142,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
if (!cpu_np) {
dev_err(&pdev->dev, "atmel,ssc-controller node missing\n");
ret = -EINVAL;
- goto out;
+ goto out_put_codec_np;
}
dai->cpus->of_node = cpu_np;
dai->platforms->of_node = cpu_np;
@@ -153,12 +153,9 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set SSC %d for audio: %d\n",
ret, priv->ssc_id);
- goto out;
+ goto out_put_cpu_np;
}
- of_node_put(codec_np);
- of_node_put(cpu_np);
-
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
dev_err(&pdev->dev, "Platform device allocation failed\n");
@@ -167,10 +164,14 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "%s ok\n", __func__);
- return ret;
+ goto out_put_cpu_np;
out_put_audio:
atmel_ssc_put_audio(priv->ssc_id);
+out_put_cpu_np:
+ of_node_put(cpu_np);
+out_put_codec_np:
+ of_node_put(codec_np);
out:
return ret;
}
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index 1b3a31296c9b..ef537de7719c 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -371,35 +371,27 @@ static int tse850_probe(struct platform_device *pdev)
}
tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH);
- if (IS_ERR(tse850->add)) {
- if (PTR_ERR(tse850->add) != -EPROBE_DEFER)
- dev_err(dev, "failed to get 'add' gpio\n");
- return PTR_ERR(tse850->add);
- }
+ if (IS_ERR(tse850->add))
+ return dev_err_probe(dev, PTR_ERR(tse850->add),
+ "failed to get 'add' gpio\n");
tse850->add_cache = 1;
tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH);
- if (IS_ERR(tse850->loop1)) {
- if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER)
- dev_err(dev, "failed to get 'loop1' gpio\n");
- return PTR_ERR(tse850->loop1);
- }
+ if (IS_ERR(tse850->loop1))
+ return dev_err_probe(dev, PTR_ERR(tse850->loop1),
+ "failed to get 'loop1' gpio\n");
tse850->loop1_cache = 1;
tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH);
- if (IS_ERR(tse850->loop2)) {
- if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER)
- dev_err(dev, "failed to get 'loop2' gpio\n");
- return PTR_ERR(tse850->loop2);
- }
+ if (IS_ERR(tse850->loop2))
+ return dev_err_probe(dev, PTR_ERR(tse850->loop2),
+ "failed to get 'loop2' gpio\n");
tse850->loop2_cache = 1;
tse850->ana = devm_regulator_get(dev, "axentia,ana");
- if (IS_ERR(tse850->ana)) {
- if (PTR_ERR(tse850->ana) != -EPROBE_DEFER)
- dev_err(dev, "failed to get 'ana' regulator\n");
- return PTR_ERR(tse850->ana);
- }
+ if (IS_ERR(tse850->ana))
+ return dev_err_probe(dev, PTR_ERR(tse850->ana),
+ "failed to get 'ana' regulator\n");
ret = regulator_enable(tse850->ana);
if (ret < 0) {
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 38de7c0efbc7..8a78809e8754 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -58,7 +58,7 @@ config SND_SOC_DB1200
select SND_SOC_AC97_CODEC
select SND_SOC_WM9712
select SND_SOC_AU1XPSC_I2S
- select SND_SOC_WM8731
+ select SND_SOC_WM8731_I2C
help
Select this option to enable audio (AC97 and I2S) on the
Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards.
diff --git a/sound/soc/bcm/bcm63xx-i2s.h b/sound/soc/bcm/bcm63xx-i2s.h
index edc328ba53d3..f30556bec89e 100644
--- a/sound/soc/bcm/bcm63xx-i2s.h
+++ b/sound/soc/bcm/bcm63xx-i2s.h
@@ -74,7 +74,6 @@
struct bcm_i2s_priv {
struct device *dev;
- struct resource *r_irq;
struct regmap *regmap_i2s;
struct clk *i2s_clk;
struct snd_pcm_substream *play_substream;
diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c
index b5096f64c576..2c600b017524 100644
--- a/sound/soc/bcm/bcm63xx-pcm-whistler.c
+++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c
@@ -6,6 +6,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/module.h>
#include <sound/pcm_params.h>
#include <linux/regmap.h>
@@ -387,14 +388,12 @@ int bcm63xx_soc_platform_probe(struct platform_device *pdev,
{
int ret;
- i2s_priv->r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!i2s_priv->r_irq) {
- dev_err(&pdev->dev, "Unable to get register irq resource.\n");
- return -ENODEV;
- }
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
- ret = devm_request_irq(&pdev->dev, i2s_priv->r_irq->start, i2s_dma_isr,
- i2s_priv->r_irq->flags, "i2s_dma", (void *)i2s_priv);
+ ret = devm_request_irq(&pdev->dev, ret, i2s_dma_isr,
+ irq_get_trigger_type(ret), "i2s_dma", (void *)i2s_priv);
if (ret) {
dev_err(&pdev->dev,
"i2s_init: failed to request interrupt.ret=%d\n", ret);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 326f2d611ad4..6165db92a629 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
@@ -125,6 +129,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 +171,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
@@ -220,6 +226,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 +248,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 +269,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
@@ -343,11 +351,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 +531,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 +585,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
@@ -609,15 +640,53 @@ 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
tristate "Cirrus Logic CS42L42 CODEC"
@@ -708,6 +777,7 @@ config SND_SOC_CS4349
config SND_SOC_CS47L15
tristate
+ depends on MFD_CS47L15
config SND_SOC_CS47L24
tristate
@@ -715,15 +785,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 +891,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.
@@ -913,7 +986,6 @@ config SND_SOC_MAX98095
config SND_SOC_MAX98357A
tristate "Maxim MAX98357A CODEC"
- depends on GPIOLIB
config SND_SOC_MAX98371
tristate
@@ -975,6 +1047,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
@@ -1173,7 +1254,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 +1408,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,11 +1451,10 @@ 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"
@@ -1460,6 +1542,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 +1577,13 @@ 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
+ help
+ Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
+ ADCs.
+
config SND_SOC_TLV320AIC23
tristate
@@ -1699,8 +1797,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 +1866,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
@@ -1869,7 +1978,6 @@ config SND_SOC_WSA881X
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 +1991,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 +2074,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 +2085,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..28dc4edfd01f 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,8 +56,14 @@ 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-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
@@ -109,6 +117,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 +139,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 +186,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
@@ -233,11 +244,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 +296,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
@@ -369,6 +384,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 +397,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,8 +408,14 @@ 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_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) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
@@ -463,6 +486,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 +533,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
@@ -567,11 +592,13 @@ obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.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 +646,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
@@ -666,6 +695,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/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/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..a9032b5c8d78 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1473,8 +1473,7 @@ static const struct snd_soc_component_driver adau1373_component_driver = {
.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 +1507,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..98768e5300f0 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);
}
@@ -783,13 +785,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 +822,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 +830,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 +877,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..0683caf86aea 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;
@@ -59,7 +61,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..8f887227981f 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;
@@ -919,6 +993,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..e046de0ebcc7 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;
@@ -55,7 +57,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/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/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/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/ak4118.c b/sound/soc/codecs/ak4118.c
index e0a6451851e8..5c4a78c16733 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -356,8 +356,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 +373,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 +415,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..9a7b662016b9
--- /dev/null
+++ b/sound/soc/codecs/ak4375.c
@@ -0,0 +1,610 @@
+// 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,
+ .non_legacy_dai_naming = 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 int ak4375_i2c_remove(struct i2c_client *i2c)
+{
+ pm_runtime_disable(&i2c->dev);
+
+ return 0;
+}
+
+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/ak4535.c b/sound/soc/codecs/ak4535.c
index 91e7a57c43da..cc803e730c6e 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -405,8 +405,7 @@ static const struct snd_soc_component_driver soc_component_dev_ak4535 = {
.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 +440,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/ak4613.c b/sound/soc/codecs/ak4613.c
index 4d2e78101f28..55e773f92122 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,
},
@@ -626,6 +835,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 +851,32 @@ 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
+ */
+ sdti_num = of_graph_get_endpoint_count(np);
+ if (WARN_ON((sdti_num > 3) || (sdti_num < 1)))
+ return;
+
+ 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 +885,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 +902,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);
@@ -699,7 +929,7 @@ static struct i2c_driver ak4613_i2c_driver = {
.name = "ak4613-codec",
.of_match_table = ak4613_of_match,
},
- .probe = ak4613_i2c_probe,
+ .probe_new = ak4613_i2c_probe,
.remove = ak4613_i2c_remove,
.id_table = ak4613_i2c_id,
};
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 04aef0e72aa5..d8d9cc712d67 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -548,8 +548,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;
@@ -632,7 +631,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..3c20ff5595eb 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -630,8 +630,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 +651,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 +699,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..60edcbe56014 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -629,8 +629,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 +656,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/alc5623.c b/sound/soc/codecs/alc5623.c
index b10357a6d655..8e6235d2c544 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -968,14 +968,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 +990,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 +1017,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 +1070,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 +1084,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..641bdfddae16 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1092,18 +1092,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 +1135,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 +1169,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 +1183,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/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/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 4d286844e3c8..cf17b9741bd8 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[] = {
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 598e09024e23..ffdf8b615efa 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -1667,6 +1667,8 @@ 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/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 9b92e1a0d1a3..8b0a9c788a26 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,
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 933e3d627e5f..badfc55bc5fa 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -346,8 +346,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 =
@@ -576,7 +575,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..47dc0f6d90a2 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -1116,8 +1116,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);
@@ -1286,7 +1285,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..50d509a06071 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -994,8 +994,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 =
@@ -1217,7 +1216,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..6b70afb70a67 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -1311,7 +1311,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 +1466,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;
@@ -1658,7 +1657,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..dfe85dc2cd20 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[] = {
@@ -1700,8 +1701,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 +1804,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)
@@ -1947,7 +1947,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..37c703c08fd5 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,7 +53,7 @@ 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)
@@ -100,11 +85,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..6d3070ea9e06
--- /dev/null
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -0,0 +1,1327 @@
+// 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, 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, 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 },
+};
+
+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 },
+};
+
+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 },
+};
+
+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;
+ }
+
+ 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);
+
+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..9e19c946a66b 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
@@ -99,6 +82,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..3e68a07a3c8e 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -13,8 +13,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 +151,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 +179,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 +306,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),
@@ -282,130 +351,10 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
SOC_SINGLE("Amp Gain ZC", 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 +363,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 +377,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 +482,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 +514,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 +546,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 +569,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 +647,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 +676,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 +921,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 +1003,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 +1014,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 +1025,133 @@ 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;
+
+ ret = wm_halo_init(dsp);
+ if (ret) {
+ dev_err(cs35l41->dev, "wm_halo_init failed: %d\n", ret);
+ return ret;
+ }
-int cs35l41_probe(struct cs35l41_private *cs35l41,
- struct cs35l41_platform_data *pdata)
+ 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;
+}
+
+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 +1236,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 +1259,233 @@ 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);
- if (ret < 0) {
- dev_err(cs35l41->dev, "OTP Unpack 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);
- goto err;
- }
-
- ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 0);
+ ret = cs35l41_set_pdata(cs35l41);
if (ret < 0) {
- dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed: %d\n", ret);
+ dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret);
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);
+ ret = cs35l41_dsp_init(cs35l41);
+ if (ret < 0)
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);
+ 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;
+
+ dev_dbg(cs35l41->dev, "Enter hibernate\n");
+
+ cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
+ regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
+ regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+ // Don't wait for ACK since bus activity would wake the device
+ regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1,
+ CSPL_MBOX_CMD_HIBERNATE);
+
+ regcache_cache_only(cs35l41->regmap, true);
+ regcache_mark_dirty(cs35l41->regmap);
+
+ return 0;
+}
+
+static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41)
+{
+ const int pwrmgt_retries = 10;
+ unsigned int sts;
+ int i, ret;
+
+ for (i = 0; i < pwrmgt_retries; i++) {
+ ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts);
+ if (ret)
+ dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret);
+ else if (!(sts & CS35L41_WR_PEND_STS_MASK))
+ return;
+
+ udelay(20);
+ }
+
+ dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n");
+}
+
+static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41)
+{
+ const int wake_retries = 20;
+ const int sleep_retries = 5;
+ int ret, i, j;
+
+ for (i = 0; i < sleep_retries; i++) {
+ dev_dbg(cs35l41->dev, "Exit hibernate\n");
+
+ for (j = 0; j < wake_retries; j++) {
+ ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
+ CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
+ if (!ret)
+ break;
+
+ usleep_range(100, 200);
+ }
+
+ if (j < wake_retries) {
+ dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j);
+ return 0;
+ }
+
+ dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret);
+
+ cs35l41_wait_for_pwrmgt_sts(cs35l41);
+ regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
+
+ cs35l41_wait_for_pwrmgt_sts(cs35l41);
+ regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+ cs35l41_wait_for_pwrmgt_sts(cs35l41);
+ regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3);
+ }
+
+ dev_err(cs35l41->dev, "Timed out waking device\n");
+
+ return -ETIMEDOUT;
+}
+
+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);
+ 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..38a4dbc9e9fe
--- /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 int cs35l45_i2c_remove(struct i2c_client *client)
+{
+ struct cs35l45_private *cs35l45 = i2c_get_clientdata(client);
+
+ return 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..2367c1a4c10e
--- /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",
+};
+
+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);
+
+int 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);
+
+ return 0;
+}
+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..4e266d19cd1c
--- /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 *cs43l45);
+unsigned int cs35l45_get_clk_freq_id(unsigned int freq);
+int cs35l45_probe(struct cs35l45_private *cs35l45);
+int 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..881c5ba70c0e 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -663,6 +663,7 @@ static const struct snd_soc_component_driver soc_component_cs4234 = {
.non_legacy_dai_naming = 1,
.idle_bias_on = 1,
.suspend_bias_off = 1,
+ .endianness = 1,
};
static const struct regmap_config cs4234_regmap = {
@@ -731,7 +732,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;
@@ -908,7 +909,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..86bfa8d5ec78 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),
@@ -569,8 +568,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 +609,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 +624,16 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
ARRAY_SIZE(cs4265_dai));
}
+static int 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);
+
+ return 0;
+}
+
static const struct of_device_id cs4265_of_match[] = {
{ .compatible = "cirrus,cs4265", },
{ }
@@ -644,7 +652,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..531f63b01554 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 */
@@ -677,8 +668,7 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client)
* 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 +755,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/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 27a1c4c73074..4fade2388797 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -42,6 +42,7 @@ static const struct reg_default cs42l42_reg_defaults[] = {
{ 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 },
@@ -177,6 +178,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:
@@ -387,6 +389,28 @@ static const struct regmap_config cs42l42_regmap = {
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 much 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 +455,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,8 +549,25 @@ 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;
}
@@ -706,10 +751,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,
@@ -971,17 +1012,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);
}
@@ -1242,10 +1291,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 +1319,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 +1341,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 +1352,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 +1405,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 +1453,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));
@@ -1589,6 +1620,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int i;
int report = 0;
+ mutex_lock(&cs42l42->irq_lock);
+ if (cs42l42->suspended) {
+ mutex_unlock(&cs42l42->irq_lock);
+ return IRQ_NONE;
+ }
/* Read sticky registers to clear interurpt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
@@ -1611,7 +1647,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 +1659,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 +1691,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);
@@ -1689,6 +1723,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
}
}
+ mutex_unlock(&cs42l42->irq_lock);
+
return IRQ_HANDLED;
}
@@ -1801,6 +1837,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,8 +2062,139 @@ 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)
+};
+
+static int __maybe_unused cs42l42_suspend(struct device *dev)
+{
+ 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;
+
+ /* 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, &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);
+
+ /* Discharge FILT+ */
+ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2,
+ CS42L42_DISCHARGE_FILT_MASK, CS42L42_DISCHARGE_FILT_MASK);
+ msleep(CS42L42_FILT_DISCHARGE_TIME_MS);
+
+ 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;
+
+}
+
+static int __maybe_unused 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);
+
+ 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");
+
+ return 0;
+}
+
+static int cs42l42_i2c_probe(struct i2c_client *i2c_client)
{
struct cs42l42_private *cs42l42;
int ret, i, devid;
@@ -2033,6 +2207,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
cs42l42->dev = &i2c_client->dev;
i2c_set_clientdata(i2c_client, cs42l42);
+ mutex_init(&cs42l42->irq_lock);
cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
if (IS_ERR(cs42l42->regmap)) {
@@ -2188,6 +2363,10 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
return 0;
}
+static const struct dev_pm_ops cs42l42_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_resume)
+};
+
#ifdef CONFIG_OF
static const struct of_device_id cs42l42_of_match[] = {
{ .compatible = "cirrus,cs42l42", },
@@ -2214,11 +2393,12 @@ MODULE_DEVICE_TABLE(i2c, cs42l42_id);
static struct i2c_driver cs42l42_i2c_driver = {
.driver = {
.name = "cs42l42",
+ .pm = &cs42l42_pm_ops,
.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,
+ .probe_new = cs42l42_i2c_probe,
.remove = cs42l42_i2c_remove,
};
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index f45bcc9a3a62..5f50970375d4 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,816 +12,9 @@
#ifndef __CS42L42_H__
#define __CS42L42_H__
+#include <linux/mutex.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
-