Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
43fc357
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
ac97
aoa
arm
atmel
core
drivers
firewire
hda
i2c
isa
mips
oss
parisc
pci
pcmcia
ppc
sh
soc
adi
amd
atmel
au1x
bcm
cirrus
codecs
88pm860x-codec.c
88pm860x-codec.h
Kconfig
Makefile
ab8500-codec.c
ab8500-codec.h
ac97.c
ad1836.c
ad1836.h
ad193x-i2c.c
ad193x-spi.c
ad193x.c
ad193x.h
ad1980.c
ad73311.c
ad73311.h
adau-utils.c
adau-utils.h
adau1372-i2c.c
adau1372-spi.c
adau1372.c
adau1372.h
adau1373.c
adau1373.h
adau1701.c
adau1701.h
adau1761-i2c.c
adau1761-spi.c
adau1761.c
adau1761.h
adau1781-i2c.c
adau1781-spi.c
adau1781.c
adau1781.h
adau17x1.c
adau17x1.h
adau1977-i2c.c
adau1977-spi.c
adau1977.c
adau1977.h
adau7002.c
adau7118-hw.c
adau7118-i2c.c
adau7118.c
adau7118.h
adav801.c
adav803.c
adav80x.c
adav80x.h
ads117x.c
ak4104.c
ak4118.c
ak4458.c
ak4458.h
ak4535.c
ak4535.h
ak4554.c
ak4613.c
ak4641.c
ak4642.c
ak4671.c
ak4671.h
ak5386.c
ak5558.c
ak5558.h
alc5623.c
alc5623.h
alc5632.c
alc5632.h
arizona.c
arizona.h
bd28623.c
bt-sco.c
cpcap.c
cq93vc.c
cros_ec_codec.c
cs35l32.c
cs35l32.h
cs35l33.c
cs35l33.h
cs35l34.c
cs35l34.h
cs35l35.c
cs35l35.h
cs35l36.c
cs35l36.h
cs4234.c
cs4234.h
cs4265.c
cs4265.h
cs4270.c
cs4271-i2c.c
cs4271-spi.c
cs4271.c
cs4271.h
cs42l42.c
cs42l42.h
cs42l51-i2c.c
cs42l51.c
cs42l51.h
cs42l52.c
cs42l52.h
cs42l56.c
cs42l56.h
cs42l73.c
cs42l73.h
cs42xx8-i2c.c
cs42xx8.c
cs42xx8.h
cs43130.c
cs43130.h
cs4341.c
cs4349.c
cs4349.h
cs47l15.c
cs47l24.c
cs47l24.h
cs47l35.c
cs47l85.c
cs47l90.c
cs47l92.c
cs53l30.c
cs53l30.h
cx20442.c
cx20442.h
cx2072x.c
cx2072x.h
da7210.c
da7213.c
da7213.h
da7218.c
da7218.h
da7219-aad.c
da7219-aad.h
da7219.c
da7219.h
da732x.c
da732x.h
da732x_reg.h
da9055.c
dmic.c
es7134.c
es7241.c
es8316.c
es8316.h
es8328-i2c.c
es8328-spi.c
es8328.c
es8328.h
gtm601.c
hdac_hda.c
hdac_hda.h
hdac_hdmi.c
hdac_hdmi.h
hdmi-codec.c
ics43432.c
inno_rk3036.c
inno_rk3036.h
isabelle.c
isabelle.h
jz4725b.c
jz4740.c
jz4760.c
jz4770.c
l3.c
lm4857.c
lm49453.c
lm49453.h
lochnagar-sc.c
lpass-rx-macro.c
lpass-tx-macro.c
lpass-va-macro.c
lpass-wsa-macro.c
lpass-wsa-macro.h
madera.c
madera.h
max9759.c
max9768.c
max98088.c
max98088.h
max98090.c
max98090.h
max98095.c
max98095.h
max98357a.c
max98371.c
max98371.h
max98373-i2c.c
max98373-sdw.c
max98373-sdw.h
max98373.c
max98373.h
max98390.c
max98390.h
max9850.c
max9850.h
max98504.c
max98504.h
max9860.c
max9860.h
max9867.c
max9867.h
max9877.c
max9877.h
max98925.c
max98925.h
max98926.c
max98926.h
max98927.c
max98927.h
mc13783.c
mc13783.h
ml26124.c
ml26124.h
msm8916-wcd-analog.c
msm8916-wcd-digital.c
mt6351.c
mt6351.h
mt6358.c
mt6358.h
mt6359.c
mt6359.h
mt6660.c
mt6660.h
nau8315.c
nau8540.c
nau8540.h
nau8810.c
nau8810.h
nau8822.c
nau8822.h
nau8824.c
nau8824.h
nau8825.c
nau8825.h
pcm1681.c
pcm1789-i2c.c
pcm1789.c
pcm1789.h
pcm179x-i2c.c
pcm179x-spi.c
pcm179x.c
pcm179x.h
pcm186x-i2c.c
pcm186x-spi.c
pcm186x.c
pcm186x.h
pcm3008.c
pcm3008.h
pcm3060-i2c.c
pcm3060-spi.c
pcm3060.c
pcm3060.h
pcm3168a-i2c.c
pcm3168a-spi.c
pcm3168a.c
pcm3168a.h
pcm5102a.c
pcm512x-i2c.c
pcm512x-spi.c
pcm512x.c
pcm512x.h
rk3328_codec.c
rk3328_codec.h
rl6231.c
rl6231.h
rl6347a.c
rl6347a.h
rt1011.c
rt1011.h
rt1015.c
rt1015.h
rt1015p.c
rt1016.c
rt1016.h
rt1305.c
rt1305.h
rt1308-sdw.c
rt1308-sdw.h
rt1308.c
rt1308.h
rt1316-sdw.c
rt1316-sdw.h
rt274.c
rt274.h
rt286.c
rt286.h
rt298.c
rt298.h
rt5514-spi.c
rt5514-spi.h
rt5514.c
rt5514.h
rt5616.c
rt5616.h
rt5631.c
rt5631.h
rt5640.c
rt5640.h
rt5645.c
rt5645.h
rt5651.c
rt5651.h
rt5659.c
rt5659.h
rt5660.c
rt5660.h
rt5663.c
rt5663.h
rt5665.c
rt5665.h
rt5668.c
rt5668.h
rt5670-dsp.h
rt5670.c
rt5670.h
rt5677-spi.c
rt5677-spi.h
rt5677.c
rt5677.h
rt5682-i2c.c
rt5682-sdw.c
rt5682.c
rt5682.h
rt700-sdw.c
rt700-sdw.h
rt700.c
rt700.h
rt711-sdca-sdw.c
rt711-sdca-sdw.h
rt711-sdca.c
rt711-sdca.h
rt711-sdw.c
rt711-sdw.h
rt711.c
rt711.h
rt715-sdca-sdw.c
rt715-sdca-sdw.h
rt715-sdca.c
rt715-sdca.h
rt715-sdw.c
rt715-sdw.h
rt715.c
rt715.h
sgtl5000.c
sgtl5000.h
si476x.c
sigmadsp-i2c.c
sigmadsp-regmap.c
sigmadsp.c
sigmadsp.h
simple-amplifier.c
simple-mux.c
spdif_receiver.c
spdif_transmitter.c
ssm2305.c
ssm2518.c
ssm2518.h
ssm2602-i2c.c
ssm2602-spi.c
ssm2602.c
ssm2602.h
ssm4567.c
sta32x.c
sta32x.h
sta350.c
sta350.h
sta529.c
stac9766.c
sti-sas.c
tas2552.c
tas2552.h
tas2562.c
tas2562.h
tas2764.c
tas2764.h
tas2770.c
tas2770.h
tas5086.c
tas571x.c
tas571x.h
tas5720.c
tas5720.h
tas6424.c
tas6424.h
tda7419.c
tfa9879.c
tfa9879.h
tlv320adcx140.c
tlv320adcx140.h
tlv320aic23-i2c.c
tlv320aic23-spi.c
tlv320aic23.c
tlv320aic23.h
tlv320aic26.c
tlv320aic26.h
tlv320aic31xx.c
tlv320aic31xx.h
tlv320aic32x4-clk.c
tlv320aic32x4-i2c.c
tlv320aic32x4-spi.c
tlv320aic32x4.c
tlv320aic32x4.h
tlv320aic3x.c
tlv320aic3x.h
tlv320dac33.c
tlv320dac33.h
tpa6130a2.c
tpa6130a2.h
ts3a227e.c
ts3a227e.h
tscs42xx.c
tscs42xx.h
tscs454.c
tscs454.h
twl4030.c
twl6040.c
twl6040.h
uda1334.c
uda134x.c
uda134x.h
uda1380.c
uda1380.h
wcd-clsh-v2.c
wcd-clsh-v2.h
wcd9335.c
wcd9335.h
wcd934x.c
wl1273.c
wl1273.h
wm0010.c
wm1250-ev1.c
wm2000.c
wm2000.h
wm2200.c
wm2200.h
wm5100-tables.c
wm5100.c
wm5100.h
wm5102.c
wm5102.h
wm5110.c
wm5110.h
wm8350.c
wm8350.h
wm8400.c
wm8400.h
wm8510.c
wm8510.h
wm8523.c
wm8523.h
wm8524.c
wm8580.c
wm8580.h
wm8711.c
wm8711.h
wm8727.c
wm8728.c
wm8728.h
wm8731.c
wm8731.h
wm8737.c
wm8737.h
wm8741.c
wm8741.h
wm8750.c
wm8750.h
wm8753.c
wm8753.h
wm8770.c
wm8770.h
wm8776.c
wm8776.h
wm8782.c
wm8804-i2c.c
wm8804-spi.c
wm8804.c
wm8804.h
wm8900.c
wm8900.h
wm8903.c
wm8903.h
wm8904.c
wm8904.h
wm8940.c
wm8940.h
wm8955.c
wm8955.h
wm8958-dsp2.c
wm8960.c
wm8960.h
wm8961.c
wm8961.h
wm8962.c
wm8962.h
wm8971.c
wm8971.h
wm8974.c
wm8974.h
wm8978.c
wm8978.h
wm8983.c
wm8983.h
wm8985.c
wm8985.h
wm8988.c
wm8988.h
wm8990.c
wm8990.h
wm8991.c
wm8991.h
wm8993.c
wm8993.h
wm8994.c
wm8994.h
wm8995.c
wm8995.h
wm8996.c
wm8996.h
wm8997.c
wm8997.h
wm8998.c
wm8998.h
wm9081.c
wm9081.h
wm9090.c
wm9090.h
wm9705.c
wm9712.c
wm9713.c
wm9713.h
wm_adsp.c
wm_adsp.h
wm_hubs.c
wm_hubs.h
wmfw.h
wsa881x.c
zl38060.c
dwc
fsl
generic
hisilicon
img
intel
jz4740
kirkwood
mediatek
meson
mxs
pxa
qcom
rockchip
samsung
sh
sof
spear
sprd
sti
stm
sunxi
tegra
ti
uniphier
ux500
xilinx
xtensa
Kconfig
Makefile
soc-ac97.c
soc-acpi.c
soc-card.c
soc-component.c
soc-compress.c
soc-core.c
soc-dai.c
soc-dapm.c
soc-devres.c
soc-generic-dmaengine-pcm.c
soc-jack.c
soc-link.c
soc-ops.c
soc-pcm.c
soc-topology-test.c
soc-topology.c
soc-utils.c
sparc
spi
synth
usb
x86
xen
Kconfig
Makefile
ac97_bus.c
last.c
sound_core.c
tools
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
sound
/
soc
/
codecs
/
cs42l42.c
Blame
Blame
Latest commit
History
History
1922 lines (1734 loc) · 56.7 KB
Breadcrumbs
linux
/
sound
/
soc
/
codecs
/
cs42l42.c
Top
File metadata and controls
Code
Blame
1922 lines (1734 loc) · 56.7 KB
Raw
// SPDX-License-Identifier: GPL-2.0-only /* * cs42l42.c -- CS42L42 ALSA SoC audio driver * * Copyright 2016 Cirrus Logic, Inc. * * Author: James Schulman <james.schulman@cirrus.com> * Author: Brian Austin <brian.austin@cirrus.com> * Author: Michael White <michael.white@cirrus.com> */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/gpio.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> #include <sound/tlv.h> #include <dt-bindings/sound/cs42l42.h> #include "cs42l42.h" static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_FRZ_CTL, 0x00 }, { CS42L42_SRC_CTL, 0x10 }, { CS42L42_MCLK_STATUS, 0x02 }, { CS42L42_MCLK_CTL, 0x02 }, { CS42L42_SFTRAMP_RATE, 0xA4 }, { CS42L42_I2C_DEBOUNCE, 0x88 }, { CS42L42_I2C_STRETCH, 0x03 }, { CS42L42_I2C_TIMEOUT, 0xB7 }, { CS42L42_PWR_CTL1, 0xFF }, { CS42L42_PWR_CTL2, 0x84 }, { CS42L42_PWR_CTL3, 0x20 }, { CS42L42_RSENSE_CTL1, 0x40 }, { CS42L42_RSENSE_CTL2, 0x00 }, { CS42L42_OSC_SWITCH, 0x00 }, { CS42L42_OSC_SWITCH_STATUS, 0x05 }, { CS42L42_RSENSE_CTL3, 0x1B }, { CS42L42_TSENSE_CTL, 0x1B }, { CS42L42_TSRS_INT_DISABLE, 0x00 }, { CS42L42_TRSENSE_STATUS, 0x00 }, { CS42L42_HSDET_CTL1, 0x77 }, { CS42L42_HSDET_CTL2, 0x00 }, { CS42L42_HS_SWITCH_CTL, 0xF3 }, { CS42L42_HS_DET_STATUS, 0x00 }, { CS42L42_HS_CLAMP_DISABLE, 0x00 }, { CS42L42_MCLK_SRC_SEL, 0x00 }, { CS42L42_SPDIF_CLK_CFG, 0x00 }, { CS42L42_FSYNC_PW_LOWER, 0x00 }, { CS42L42_FSYNC_PW_UPPER, 0x00 }, { CS42L42_FSYNC_P_LOWER, 0xF9 }, { CS42L42_FSYNC_P_UPPER, 0x00 }, { CS42L42_ASP_CLK_CFG, 0x00 }, { CS42L42_ASP_FRM_CFG, 0x10 }, { CS42L42_FS_RATE_EN, 0x00 }, { CS42L42_IN_ASRC_CLK, 0x00 }, { CS42L42_OUT_ASRC_CLK, 0x00 }, { CS42L42_PLL_DIV_CFG1, 0x00 }, { CS42L42_ADC_OVFL_STATUS, 0x00 }, { CS42L42_MIXER_STATUS, 0x00 }, { CS42L42_SRC_STATUS, 0x00 }, { CS42L42_ASP_RX_STATUS, 0x00 }, { CS42L42_ASP_TX_STATUS, 0x00 }, { CS42L42_CODEC_STATUS, 0x00 }, { CS42L42_DET_INT_STATUS1, 0x00 }, { CS42L42_DET_INT_STATUS2, 0x00 }, { CS42L42_SRCPL_INT_STATUS, 0x00 }, { CS42L42_VPMON_STATUS, 0x00 }, { CS42L42_PLL_LOCK_STATUS, 0x00 }, { CS42L42_TSRS_PLUG_STATUS, 0x00 }, { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, { CS42L42_MIXER_INT_MASK, 0x0F }, { CS42L42_SRC_INT_MASK, 0x0F }, { CS42L42_ASP_RX_INT_MASK, 0x1F }, { CS42L42_ASP_TX_INT_MASK, 0x0F }, { CS42L42_CODEC_INT_MASK, 0x03 }, { CS42L42_SRCPL_INT_MASK, 0xFF }, { CS42L42_VPMON_INT_MASK, 0x01 }, { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, { CS42L42_PLL_CTL1, 0x00 }, { CS42L42_PLL_DIV_FRAC0, 0x00 }, { CS42L42_PLL_DIV_FRAC1, 0x00 }, { CS42L42_PLL_DIV_FRAC2, 0x00 }, { CS42L42_PLL_DIV_INT, 0x40 }, { CS42L42_PLL_CTL3, 0x10 }, { CS42L42_PLL_CAL_RATIO, 0x80 }, { CS42L42_PLL_CTL4, 0x03 }, { CS42L42_LOAD_DET_RCSTAT, 0x00 }, { CS42L42_LOAD_DET_DONE, 0x00 }, { CS42L42_LOAD_DET_EN, 0x00 }, { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, { CS42L42_WAKE_CTL, 0xC0 }, { CS42L42_ADC_DISABLE_MUTE, 0x00 }, { CS42L42_TIPSENSE_CTL, 0x02 }, { CS42L42_MISC_DET_CTL, 0x03 }, { CS42L42_MIC_DET_CTL1, 0x1F }, { CS42L42_MIC_DET_CTL2, 0x2F }, { CS42L42_DET_STATUS1, 0x00 }, { CS42L42_DET_STATUS2, 0x00 }, { CS42L42_DET_INT1_MASK, 0xE0 }, { CS42L42_DET_INT2_MASK, 0xFF }, { CS42L42_HS_BIAS_CTL, 0xC2 }, { CS42L42_ADC_CTL, 0x00 }, { CS42L42_ADC_VOLUME, 0x00 }, { CS42L42_ADC_WNF_HPF_CTL, 0x71 }, { CS42L42_DAC_CTL1, 0x00 }, { CS42L42_DAC_CTL2, 0x02 }, { CS42L42_HP_CTL, 0x0D }, { CS42L42_CLASSH_CTL, 0x07 }, { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, { CS42L42_EQ_COEF_IN0, 0x22 }, { CS42L42_EQ_COEF_IN1, 0x00 }, { CS42L42_EQ_COEF_IN2, 0x00 }, { CS42L42_EQ_COEF_IN3, 0x00 }, { CS42L42_EQ_COEF_RW, 0x00 }, { CS42L42_EQ_COEF_OUT0, 0x00 }, { CS42L42_EQ_COEF_OUT1, 0x00 }, { CS42L42_EQ_COEF_OUT2, 0x00 }, { CS42L42_EQ_COEF_OUT3, 0x00 }, { CS42L42_EQ_INIT_STAT, 0x00 }, { CS42L42_EQ_START_FILT, 0x00 }, { CS42L42_EQ_MUTE_CTL, 0x00 }, { CS42L42_SP_RX_CH_SEL, 0x04 }, { CS42L42_SP_RX_ISOC_CTL, 0x04 }, { CS42L42_SP_RX_FS, 0x8C }, { CS42l42_SPDIF_CH_SEL, 0x0E }, { CS42L42_SP_TX_ISOC_CTL, 0x04 }, { CS42L42_SP_TX_FS, 0xCC }, { CS42L42_SPDIF_SW_CTL1, 0x3F }, { CS42L42_SRC_SDIN_FS, 0x40 }, { CS42L42_SRC_SDOUT_FS, 0x40 }, { CS42L42_SPDIF_CTL1, 0x01 }, { CS42L42_SPDIF_CTL2, 0x00 }, { CS42L42_SPDIF_CTL3, 0x00 }, { CS42L42_SPDIF_CTL4, 0x42 }, { CS42L42_ASP_TX_SZ_EN, 0x00 }, { CS42L42_ASP_TX_CH_EN, 0x00 }, { CS42L42_ASP_TX_CH_AP_RES, 0x0F }, { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 }, { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 }, { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI0_EN, 0x00 }, { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 }, { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, { CS42L42_SUB_REVID, 0x03 }, }; static bool cs42l42_readable_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_PAGE_REGISTER: case CS42L42_DEVID_AB: case CS42L42_DEVID_CD: case CS42L42_DEVID_E: case CS42L42_FABID: case CS42L42_REVID: case CS42L42_FRZ_CTL: case CS42L42_SRC_CTL: case CS42L42_MCLK_STATUS: case CS42L42_MCLK_CTL: case CS42L42_SFTRAMP_RATE: case CS42L42_I2C_DEBOUNCE: case CS42L42_I2C_STRETCH: case CS42L42_I2C_TIMEOUT: case CS42L42_PWR_CTL1: case CS42L42_PWR_CTL2: case CS42L42_PWR_CTL3: case CS42L42_RSENSE_CTL1: case CS42L42_RSENSE_CTL2: case CS42L42_OSC_SWITCH: case CS42L42_OSC_SWITCH_STATUS: case CS42L42_RSENSE_CTL3: case CS42L42_TSENSE_CTL: case CS42L42_TSRS_INT_DISABLE: case CS42L42_TRSENSE_STATUS: case CS42L42_HSDET_CTL1: case CS42L42_HSDET_CTL2: case CS42L42_HS_SWITCH_CTL: case CS42L42_HS_DET_STATUS: case CS42L42_HS_CLAMP_DISABLE: case CS42L42_MCLK_SRC_SEL: case CS42L42_SPDIF_CLK_CFG: case CS42L42_FSYNC_PW_LOWER: case CS42L42_FSYNC_PW_UPPER: case CS42L42_FSYNC_P_LOWER: case CS42L42_FSYNC_P_UPPER: case CS42L42_ASP_CLK_CFG: case CS42L42_ASP_FRM_CFG: case CS42L42_FS_RATE_EN: case CS42L42_IN_ASRC_CLK: case CS42L42_OUT_ASRC_CLK: case CS42L42_PLL_DIV_CFG1: case CS42L42_ADC_OVFL_STATUS: case CS42L42_MIXER_STATUS: case CS42L42_SRC_STATUS: case CS42L42_ASP_RX_STATUS: case CS42L42_ASP_TX_STATUS: case CS42L42_CODEC_STATUS: case CS42L42_DET_INT_STATUS1: case CS42L42_DET_INT_STATUS2: case CS42L42_SRCPL_INT_STATUS: case CS42L42_VPMON_STATUS: case CS42L42_PLL_LOCK_STATUS: case CS42L42_TSRS_PLUG_STATUS: case CS42L42_ADC_OVFL_INT_MASK: case CS42L42_MIXER_INT_MASK: case CS42L42_SRC_INT_MASK: case CS42L42_ASP_RX_INT_MASK: case CS42L42_ASP_TX_INT_MASK: case CS42L42_CODEC_INT_MASK: case CS42L42_SRCPL_INT_MASK: case CS42L42_VPMON_INT_MASK: case CS42L42_PLL_LOCK_INT_MASK: case CS42L42_TSRS_PLUG_INT_MASK: case CS42L42_PLL_CTL1: case CS42L42_PLL_DIV_FRAC0: case CS42L42_PLL_DIV_FRAC1: case CS42L42_PLL_DIV_FRAC2: case CS42L42_PLL_DIV_INT: case CS42L42_PLL_CTL3: case CS42L42_PLL_CAL_RATIO: case CS42L42_PLL_CTL4: case CS42L42_LOAD_DET_RCSTAT: case CS42L42_LOAD_DET_DONE: case CS42L42_LOAD_DET_EN: case CS42L42_HSBIAS_SC_AUTOCTL: case CS42L42_WAKE_CTL: case CS42L42_ADC_DISABLE_MUTE: case CS42L42_TIPSENSE_CTL: case CS42L42_MISC_DET_CTL: case CS42L42_MIC_DET_CTL1: case CS42L42_MIC_DET_CTL2: case CS42L42_DET_STATUS1: case CS42L42_DET_STATUS2: case CS42L42_DET_INT1_MASK: case CS42L42_DET_INT2_MASK: case CS42L42_HS_BIAS_CTL: case CS42L42_ADC_CTL: case CS42L42_ADC_VOLUME: case CS42L42_ADC_WNF_HPF_CTL: case CS42L42_DAC_CTL1: case CS42L42_DAC_CTL2: case CS42L42_HP_CTL: case CS42L42_CLASSH_CTL: case CS42L42_MIXER_CHA_VOL: case CS42L42_MIXER_ADC_VOL: case CS42L42_MIXER_CHB_VOL: case CS42L42_EQ_COEF_IN0: case CS42L42_EQ_COEF_IN1: case CS42L42_EQ_COEF_IN2: case CS42L42_EQ_COEF_IN3: case CS42L42_EQ_COEF_RW: case CS42L42_EQ_COEF_OUT0: case CS42L42_EQ_COEF_OUT1: case CS42L42_EQ_COEF_OUT2: case CS42L42_EQ_COEF_OUT3: case CS42L42_EQ_INIT_STAT: case CS42L42_EQ_START_FILT: case CS42L42_EQ_MUTE_CTL: case CS42L42_SP_RX_CH_SEL: case CS42L42_SP_RX_ISOC_CTL: case CS42L42_SP_RX_FS: case CS42l42_SPDIF_CH_SEL: case CS42L42_SP_TX_ISOC_CTL: case CS42L42_SP_TX_FS: case CS42L42_SPDIF_SW_CTL1: case CS42L42_SRC_SDIN_FS: case CS42L42_SRC_SDOUT_FS: case CS42L42_SPDIF_CTL1: case CS42L42_SPDIF_CTL2: case CS42L42_SPDIF_CTL3: case CS42L42_SPDIF_CTL4: case CS42L42_ASP_TX_SZ_EN: case CS42L42_ASP_TX_CH_EN: case CS42L42_ASP_TX_CH_AP_RES: case CS42L42_ASP_TX_CH1_BIT_MSB: case CS42L42_ASP_TX_CH1_BIT_LSB: case CS42L42_ASP_TX_HIZ_DLY_CFG: case CS42L42_ASP_TX_CH2_BIT_MSB: case CS42L42_ASP_TX_CH2_BIT_LSB: case CS42L42_ASP_RX_DAI0_EN: case CS42L42_ASP_RX_DAI0_CH1_AP_RES: case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB: case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB: case CS42L42_ASP_RX_DAI0_CH2_AP_RES: case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB: case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB: case CS42L42_ASP_RX_DAI0_CH3_AP_RES: case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB: case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB: case CS42L42_ASP_RX_DAI0_CH4_AP_RES: case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB: case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB: case CS42L42_ASP_RX_DAI1_CH1_AP_RES: case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB: case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB: case CS42L42_ASP_RX_DAI1_CH2_AP_RES: case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB: case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB: case CS42L42_SUB_REVID: return true; default: return false; } } static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_DEVID_AB: case CS42L42_DEVID_CD: case CS42L42_DEVID_E: case CS42L42_MCLK_STATUS: case CS42L42_TRSENSE_STATUS: case CS42L42_HS_DET_STATUS: case CS42L42_ADC_OVFL_STATUS: case CS42L42_MIXER_STATUS: case CS42L42_SRC_STATUS: case CS42L42_ASP_RX_STATUS: case CS42L42_ASP_TX_STATUS: case CS42L42_CODEC_STATUS: case CS42L42_DET_INT_STATUS1: case CS42L42_DET_INT_STATUS2: case CS42L42_SRCPL_INT_STATUS: case CS42L42_VPMON_STATUS: case CS42L42_PLL_LOCK_STATUS: case CS42L42_TSRS_PLUG_STATUS: case CS42L42_LOAD_DET_RCSTAT: case CS42L42_LOAD_DET_DONE: case CS42L42_DET_STATUS1: case CS42L42_DET_STATUS2: return true; default: return false; } } static const struct regmap_range_cfg cs42l42_page_range = { .name = "Pages", .range_min = 0, .range_max = CS42L42_MAX_REGISTER, .selector_reg = CS42L42_PAGE_REGISTER, .selector_mask = 0xff, .selector_shift = 0, .window_start = 0, .window_len = 256, }; static const struct regmap_config cs42l42_regmap = { .reg_bits = 8, .val_bits = 8, .readable_reg = cs42l42_readable_register, .volatile_reg = cs42l42_volatile_register, .ranges = &cs42l42_page_range, .num_ranges = 1, .max_register = CS42L42_MAX_REGISTER, .reg_defaults = cs42l42_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), .cache_type = REGCACHE_RBTREE, }; static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); static const char * const cs42l42_hpf_freq_text[] = { "1.86Hz", "120Hz", "235Hz", "466Hz" }; static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL, CS42L42_ADC_HPF_CF_SHIFT, cs42l42_hpf_freq_text); static const char * const cs42l42_wnf3_freq_text[] = { "160Hz", "180Hz", "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz" }; static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL, CS42L42_ADC_WNF_CF_SHIFT, cs42l42_wnf3_freq_text); static const char * const cs42l42_wnf05_freq_text[] = { "280Hz", "315Hz", "350Hz", "385Hz", "420Hz", "455Hz", "490Hz", "525Hz" }; static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL, CS42L42_ADC_WNF_CF_SHIFT, cs42l42_wnf05_freq_text); static const struct snd_kcontrol_new cs42l42_snd_controls[] = { /* ADC Volume and Filter Controls */ SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL, CS42L42_ADC_NOTCH_DIS_SHIFT, true, false), SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL, CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false), SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL, CS42L42_ADC_INV_SHIFT, true, false), SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL, CS42L42_ADC_DIG_BOOST_SHIFT, true, false), SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME, CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv), SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL, CS42L42_ADC_WNF_EN_SHIFT, true, false), SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL, CS42L42_ADC_HPF_EN_SHIFT, true, false), SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum), SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum), SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum), /* DAC Volume and Filter Controls */ SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1, CS42L42_DACA_INV_SHIFT, true, false), SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1, CS42L42_DACB_INV_SHIFT, true, false), SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2, 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) }; static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { /* Playback Path */ SND_SOC_DAPM_OUTPUT("HP"), SND_SOC_DAPM_DAC("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1), SND_SOC_DAPM_MIXER("MIXER", CS42L42_PWR_CTL1, CS42L42_MIXER_PDN_SHIFT, 1, NULL, 0), SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH1_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH2_SHIFT, 0), /* Playback Requirements */ SND_SOC_DAPM_SUPPLY("ASP DAI0", CS42L42_PWR_CTL1, CS42L42_ASP_DAI_PDN_SHIFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0), }; static const struct snd_soc_dapm_route cs42l42_audio_map[] = { /* Playback Path */ {"HP", NULL, "DAC"}, {"DAC", NULL, "MIXER"}, {"MIXER", NULL, "SDIN1"}, {"MIXER", NULL, "SDIN2"}, {"SDIN1", NULL, "Playback"}, {"SDIN2", NULL, "Playback"}, /* Playback Requirements */ {"SDIN1", NULL, "ASP DAI0"}, {"SDIN2", NULL, "ASP DAI0"}, {"SDIN1", NULL, "SCLK"}, {"SDIN2", NULL, "SCLK"}, }; static int cs42l42_component_probe(struct snd_soc_component *component) { struct cs42l42_private *cs42l42 = (struct cs42l42_private *)snd_soc_component_get_drvdata(component); cs42l42->component = component; return 0; } static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .probe = cs42l42_component_probe, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), .dapm_routes = cs42l42_audio_map, .num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map), .controls = cs42l42_snd_controls, .num_controls = ARRAY_SIZE(cs42l42_snd_controls), .idle_bias_on = 1, .endianness = 1, .non_legacy_dai_naming = 1, }; struct cs42l42_pll_params { u32 sclk; u8 mclk_div; u8 mclk_src_sel; u8 sclk_prediv; u8 pll_div_int; u32 pll_div_frac; u8 pll_mode; u8 pll_divout; u32 mclk_int; u8 pll_cal_ratio; }; /* * Common PLL Settings for given SCLK * Table 4-5 from the Datasheet */ static const struct cs42l42_pll_params pll_ratio_table[] = { { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 }, { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 }, { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 }, { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 }, { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 }, { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 }, { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 }, { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 }, { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 } }; static int cs42l42_pll_config(struct snd_soc_component *component) { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); int i; u32 fsync; for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { if (pll_ratio_table[i].sclk == cs42l42->sclk) { /* Configure the internal sample rate */ snd_soc_component_update_bits(component, CS42L42_MCLK_CTL, CS42L42_INTERNAL_FS_MASK, ((pll_ratio_table[i].mclk_int != 12000000) && (pll_ratio_table[i].mclk_int != 24000000)) << CS42L42_INTERNAL_FS_SHIFT); /* Set the MCLK src (PLL or SCLK) and the divide * ratio */ snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL, CS42L42_MCLK_SRC_SEL_MASK | CS42L42_MCLKDIV_MASK, (pll_ratio_table[i].mclk_src_sel << CS42L42_MCLK_SRC_SEL_SHIFT) | (pll_ratio_table[i].mclk_div << CS42L42_MCLKDIV_SHIFT)); /* Set up the LRCLK */ fsync = cs42l42->sclk / cs42l42->srate; if (((fsync * cs42l42->srate) != cs42l42->sclk) || ((fsync % 2) != 0)) { dev_err(component->dev, "Unsupported sclk %d/sample rate %d\n", cs42l42->sclk, cs42l42->srate); return -EINVAL; } /* Set the LRCLK period */ snd_soc_component_update_bits(component, CS42L42_FSYNC_P_LOWER, CS42L42_FSYNC_PERIOD_MASK, CS42L42_FRAC0_VAL(fsync - 1) << CS42L42_FSYNC_PERIOD_SHIFT); snd_soc_component_update_bits(component, CS42L42_FSYNC_P_UPPER, CS42L42_FSYNC_PERIOD_MASK, CS42L42_FRAC1_VAL(fsync - 1) << CS42L42_FSYNC_PERIOD_SHIFT); /* Set the LRCLK to 50% duty cycle */ fsync = fsync / 2; snd_soc_component_update_bits(component, CS42L42_FSYNC_PW_LOWER, CS42L42_FSYNC_PULSE_WIDTH_MASK, CS42L42_FRAC0_VAL(fsync - 1) << CS42L42_FSYNC_PULSE_WIDTH_SHIFT); snd_soc_component_update_bits(component, CS42L42_FSYNC_PW_UPPER, CS42L42_FSYNC_PULSE_WIDTH_MASK, CS42L42_FRAC1_VAL(fsync - 1) << CS42L42_FSYNC_PULSE_WIDTH_SHIFT); snd_soc_component_update_bits(component, CS42L42_ASP_FRM_CFG, CS42L42_ASP_5050_MASK, CS42L42_ASP_5050_MASK); /* Set the frame delay to 1.0 SCLK clocks */ snd_soc_component_update_bits(component, CS42L42_ASP_FRM_CFG, CS42L42_ASP_FSD_MASK, CS42L42_ASP_FSD_1_0 << CS42L42_ASP_FSD_SHIFT); /* Set the sample rates (96k or lower) */ snd_soc_component_update_bits(component, CS42L42_FS_RATE_EN, CS42L42_FS_EN_MASK, (CS42L42_FS_EN_IASRC_96K | CS42L42_FS_EN_OASRC_96K) << CS42L42_FS_EN_SHIFT); /* Set the input/output internal MCLK clock ~12 MHz */ snd_soc_component_update_bits(component, CS42L42_IN_ASRC_CLK, CS42L42_CLK_IASRC_SEL_MASK, CS42L42_CLK_IASRC_SEL_12 << CS42L42_CLK_IASRC_SEL_SHIFT); snd_soc_component_update_bits(component, CS42L42_OUT_ASRC_CLK, CS42L42_CLK_OASRC_SEL_MASK, CS42L42_CLK_OASRC_SEL_12 << CS42L42_CLK_OASRC_SEL_SHIFT); if (pll_ratio_table[i].mclk_src_sel == 0) { /* Pass the clock straight through */ snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 0); } else { /* Configure PLL per table 4-5 */ snd_soc_component_update_bits(component, CS42L42_PLL_DIV_CFG1, CS42L42_SCLK_PREDIV_MASK, pll_ratio_table[i].sclk_prediv << CS42L42_SCLK_PREDIV_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_DIV_INT, CS42L42_PLL_DIV_INT_MASK, pll_ratio_table[i].pll_div_int << CS42L42_PLL_DIV_INT_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_DIV_FRAC0, CS42L42_PLL_DIV_FRAC_MASK, CS42L42_FRAC0_VAL( pll_ratio_table[i].pll_div_frac) << CS42L42_PLL_DIV_FRAC_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_DIV_FRAC1, CS42L42_PLL_DIV_FRAC_MASK, CS42L42_FRAC1_VAL( pll_ratio_table[i].pll_div_frac) << CS42L42_PLL_DIV_FRAC_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_DIV_FRAC2, CS42L42_PLL_DIV_FRAC_MASK, CS42L42_FRAC2_VAL( pll_ratio_table[i].pll_div_frac) << CS42L42_PLL_DIV_FRAC_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_CTL4, CS42L42_PLL_MODE_MASK, pll_ratio_table[i].pll_mode << CS42L42_PLL_MODE_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_CTL3, CS42L42_PLL_DIVOUT_MASK, pll_ratio_table[i].pll_divout << CS42L42_PLL_DIVOUT_SHIFT); snd_soc_component_update_bits(component, CS42L42_PLL_CAL_RATIO, CS42L42_PLL_CAL_RATIO_MASK, pll_ratio_table[i].pll_cal_ratio << CS42L42_PLL_CAL_RATIO_SHIFT); } return 0; } } return -EINVAL; } static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; u32 asp_cfg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFM: asp_cfg_val |= CS42L42_ASP_MASTER_MODE << CS42L42_ASP_MODE_SHIFT; break; case SND_SOC_DAIFMT_CBS_CFS: asp_cfg_val |= CS42L42_ASP_SLAVE_MODE << CS42L42_ASP_MODE_SHIFT; break; default: return -EINVAL; } /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_LEFT_J: break; default: return -EINVAL; } /* Bitclock/frame inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT; break; case SND_SOC_DAIFMT_NB_IF: asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT; asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT; break; case SND_SOC_DAIFMT_IB_NF: break; case SND_SOC_DAIFMT_IB_IF: asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT; break; } snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, CS42L42_ASP_MODE_MASK | CS42L42_ASP_SCPOL_MASK | CS42L42_ASP_LCPOL_MASK, asp_cfg_val); return 0; } static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int width = (params_width(params) / 8) - 1; unsigned int val = 0; cs42l42->srate = params_rate(params); switch(substream->stream) { case SNDRV_PCM_STREAM_PLAYBACK: val |= width << CS42L42_ASP_RX_CH_RES_SHIFT; /* channel 1 on low LRCLK */ snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH1_AP_RES, CS42L42_ASP_RX_CH_AP_MASK | CS42L42_ASP_RX_CH_RES_MASK, val); /* Channel 2 on high LRCLK */ val |= CS42L42_ASP_RX_CH_AP_HI << CS42L42_ASP_RX_CH_AP_SHIFT; snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH2_AP_RES, CS42L42_ASP_RX_CH_AP_MASK | CS42L42_ASP_RX_CH_RES_MASK, val); break; default: break; } return cs42l42_pll_config(component); } static int cs42l42_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); cs42l42->sclk = freq; return 0; } static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int regval; u8 fullScaleVol; if (mute) { /* Mute the headphone */ if (stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_component_update_bits(component, CS42L42_HP_CTL, CS42L42_HP_ANA_AMUTE_MASK | CS42L42_HP_ANA_BMUTE_MASK, CS42L42_HP_ANA_AMUTE_MASK | CS42L42_HP_ANA_BMUTE_MASK); cs42l42->stream_use &= ~(1 << stream); if(!cs42l42->stream_use) { /* * Switch to the internal oscillator. * SCLK must remain running until after this clock switch. * Without a source of clock the I2C bus doesn't work. */ snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, CS42L42_SCLK_PRESENT_MASK, 0); snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 0); } } else { if (!cs42l42->stream_use) { /* SCLK must be running before codec unmute */ snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 1); /* Mark SCLK as present, turn off internal oscillator */ snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, CS42L42_SCLK_PRESENT_MASK, CS42L42_SCLK_PRESENT_MASK); } cs42l42->stream_use |= 1 << stream; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Read the headphone load */ regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT); if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) { fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; } else { fullScaleVol = 0; } /* Un-mute the headphone, set the full scale volume flag */ snd_soc_component_update_bits(component, CS42L42_HP_CTL, CS42L42_HP_ANA_AMUTE_MASK | CS42L42_HP_ANA_BMUTE_MASK | CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); } } return 0; } #define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ SNDRV_PCM_FMTBIT_S32_LE ) static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, .mute_stream = cs42l42_mute_stream, }; static struct snd_soc_dai_driver cs42l42_dai = { .name = "cs42l42", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = CS42L42_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = CS42L42_FORMATS, }, .ops = &cs42l42_ops, }; static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) { unsigned int hs_det_status; unsigned int int_status; /* Mask the auto detect interrupt */ regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, CS42L42_PDN_DONE_MASK | CS42L42_HSDET_AUTO_DONE_MASK, (1 << CS42L42_PDN_DONE_SHIFT) | (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); /* Set hs detect to automatic, disabled mode */ regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, CS42L42_HSDET_CTRL_MASK | CS42L42_HSDET_SET_MASK | CS42L42_HSBIAS_REF_MASK | CS42L42_HSDET_AUTO_TIME_MASK, (2 << CS42L42_HSDET_CTRL_SHIFT) | (2 << CS42L42_HSDET_SET_SHIFT) | (0 << CS42L42_HSBIAS_REF_SHIFT) | (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); /* Read and save the hs detection result */ regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> CS42L42_HSDET_TYPE_SHIFT; /* Set up button detection */ if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) || (cs42l42->hs_type == CS42L42_PLUG_OMTP)) { /* Set auto HS bias settings to default */ regmap_update_bits(cs42l42->regmap, CS42L42_HSBIAS_SC_AUTOCTL, CS42L42_HSBIAS_SENSE_EN_MASK | CS42L42_AUTO_HSBIAS_HIZ_MASK | CS42L42_TIP_SENSE_EN_MASK | CS42L42_HSBIAS_SENSE_TRIP_MASK, (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | (0 << CS42L42_TIP_SENSE_EN_SHIFT) | (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); /* Set up hs detect level sensitivity */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | CS42L42_EVENT_STAT_SEL_MASK | CS42L42_HS_DET_LEVEL_MASK, (1 << CS42L42_LATCH_TO_VP_SHIFT) | (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); /* Set auto HS bias settings to default */ regmap_update_bits(cs42l42->regmap, CS42L42_HSBIAS_SC_AUTOCTL, CS42L42_HSBIAS_SENSE_EN_MASK | CS42L42_AUTO_HSBIAS_HIZ_MASK | CS42L42_TIP_SENSE_EN_MASK | CS42L42_HSBIAS_SENSE_TRIP_MASK, (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | (0 << CS42L42_TIP_SENSE_EN_SHIFT) | (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); /* 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)); msleep(cs42l42->btn_det_init_dbnce); /* Clear any button interrupts before unmasking them */ regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, &int_status); /* Unmask button detect interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK | CS42L42_M_SHORT_RLS_MASK | CS42L42_M_SHORT_DET_MASK, (0 << CS42L42_M_DETECT_TF_SHIFT) | (0 << CS42L42_M_DETECT_FT_SHIFT) | (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); } else { /* 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)); } regmap_update_bits(cs42l42->regmap, CS42L42_DAC_CTL2, CS42L42_HPOUT_PULLDOWN_MASK | CS42L42_HPOUT_LOAD_MASK | CS42L42_HPOUT_CLAMP_MASK | CS42L42_DAC_HPF_EN_MASK | CS42L42_DAC_MON_EN_MASK, (0 << CS42L42_HPOUT_PULLDOWN_SHIFT) | (0 << CS42L42_HPOUT_LOAD_SHIFT) | (0 << CS42L42_HPOUT_CLAMP_SHIFT) | (1 << CS42L42_DAC_HPF_EN_SHIFT) | (0 << CS42L42_DAC_MON_EN_SHIFT)); /* 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)); } 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)); /* Set auto HS bias settings to default */ regmap_update_bits(cs42l42->regmap, CS42L42_HSBIAS_SC_AUTOCTL, CS42L42_HSBIAS_SENSE_EN_MASK | CS42L42_AUTO_HSBIAS_HIZ_MASK | CS42L42_TIP_SENSE_EN_MASK | CS42L42_HSBIAS_SENSE_TRIP_MASK, (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | (0 << CS42L42_TIP_SENSE_EN_SHIFT) | (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); /* Set hs detect to manual, disabled mode */ regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, CS42L42_HSDET_CTRL_MASK | CS42L42_HSDET_SET_MASK | CS42L42_HSBIAS_REF_MASK | CS42L42_HSDET_AUTO_TIME_MASK, (0 << CS42L42_HSDET_CTRL_SHIFT) | (2 << CS42L42_HSDET_SET_SHIFT) | (0 << CS42L42_HSBIAS_REF_SHIFT) | (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_DAC_CTL2, CS42L42_HPOUT_PULLDOWN_MASK | CS42L42_HPOUT_LOAD_MASK | CS42L42_HPOUT_CLAMP_MASK | CS42L42_DAC_HPF_EN_MASK | CS42L42_DAC_MON_EN_MASK, (8 << CS42L42_HPOUT_PULLDOWN_SHIFT) | (0 << CS42L42_HPOUT_LOAD_SHIFT) | (1 << CS42L42_HPOUT_CLAMP_SHIFT) | (1 << CS42L42_DAC_HPF_EN_SHIFT) | (1 << CS42L42_DAC_MON_EN_SHIFT)); /* 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)); /* Wait for HS bias to ramp up */ msleep(cs42l42->hs_bias_ramp_time); /* Unmask auto detect interrupt */ regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, CS42L42_PDN_DONE_MASK | CS42L42_HSDET_AUTO_DONE_MASK, (1 << CS42L42_PDN_DONE_SHIFT) | (0 << CS42L42_HSDET_AUTO_DONE_SHIFT)); /* Set hs detect to automatic, enabled mode */ regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, CS42L42_HSDET_CTRL_MASK | CS42L42_HSDET_SET_MASK | CS42L42_HSBIAS_REF_MASK | CS42L42_HSDET_AUTO_TIME_MASK, (3 << CS42L42_HSDET_CTRL_SHIFT) | (2 << CS42L42_HSDET_SET_SHIFT) | (0 << CS42L42_HSBIAS_REF_SHIFT) | (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); } static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) { /* Mask button detect interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK | CS42L42_M_SHORT_RLS_MASK | CS42L42_M_SHORT_DET_MASK, (1 << CS42L42_M_DETECT_TF_SHIFT) | (1 << CS42L42_M_DETECT_FT_SHIFT) | (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); /* 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)); /* Set auto HS bias settings to default */ regmap_update_bits(cs42l42->regmap, CS42L42_HSBIAS_SC_AUTOCTL, CS42L42_HSBIAS_SENSE_EN_MASK | CS42L42_AUTO_HSBIAS_HIZ_MASK | CS42L42_TIP_SENSE_EN_MASK | CS42L42_HSBIAS_SENSE_TRIP_MASK, (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | (0 << CS42L42_TIP_SENSE_EN_SHIFT) | (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); /* Set hs detect to manual, disabled mode */ regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, CS42L42_HSDET_CTRL_MASK | CS42L42_HSDET_SET_MASK | CS42L42_HSBIAS_REF_MASK | CS42L42_HSDET_AUTO_TIME_MASK, (0 << CS42L42_HSDET_CTRL_SHIFT) | (2 << CS42L42_HSDET_SET_SHIFT) | (0 << CS42L42_HSBIAS_REF_SHIFT) | (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); } static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) { int bias_level; unsigned int detect_status; /* Mask button detect interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK | CS42L42_M_SHORT_RLS_MASK | CS42L42_M_SHORT_DET_MASK, (1 << CS42L42_M_DETECT_TF_SHIFT) | (1 << CS42L42_M_DETECT_FT_SHIFT) | (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); usleep_range(cs42l42->btn_det_event_dbnce * 1000, cs42l42->btn_det_event_dbnce * 2000); /* Test all 4 level detect biases */ bias_level = 1; do { /* Adjust button detect level sensitivity */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | CS42L42_EVENT_STAT_SEL_MASK | CS42L42_HS_DET_LEVEL_MASK, (1 << CS42L42_LATCH_TO_VP_SHIFT) | (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | (cs42l42->bias_thresholds[bias_level] << CS42L42_HS_DET_LEVEL_SHIFT)); regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2, &detect_status); } while ((detect_status & CS42L42_HS_TRUE_MASK) && (++bias_level < CS42L42_NUM_BIASES)); switch (bias_level) { case 1: /* Function C button press */ dev_dbg(cs42l42->component->dev, "Function C button press\n"); break; case 2: /* Function B button press */ dev_dbg(cs42l42->component->dev, "Function B button press\n"); break; case 3: /* Function D button press */ dev_dbg(cs42l42->component->dev, "Function D button press\n"); break; case 4: /* Function A button press */ dev_dbg(cs42l42->component->dev, "Function A button press\n"); break; } /* Set button detect level sensitivity back to default */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | CS42L42_EVENT_STAT_SEL_MASK | CS42L42_HS_DET_LEVEL_MASK, (1 << CS42L42_LATCH_TO_VP_SHIFT) | (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); /* Clear any button interrupts before unmasking them */ regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, &detect_status); /* Unmask button detect interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK | CS42L42_M_SHORT_RLS_MASK | CS42L42_M_SHORT_DET_MASK, (0 << CS42L42_M_DETECT_TF_SHIFT) | (0 << CS42L42_M_DETECT_FT_SHIFT) | (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); } struct cs42l42_irq_params { u16 status_addr; u16 mask_addr; u8 mask; }; static const struct cs42l42_irq_params irq_params_table[] = { {CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK, CS42L42_ADC_OVFL_VAL_MASK}, {CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK, CS42L42_MIXER_VAL_MASK}, {CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK, CS42L42_SRC_VAL_MASK}, {CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK, CS42L42_ASP_RX_VAL_MASK}, {CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK, CS42L42_ASP_TX_VAL_MASK}, {CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK, CS42L42_CODEC_VAL_MASK}, {CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK, CS42L42_DET_INT_VAL1_MASK}, {CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK, CS42L42_DET_INT_VAL2_MASK}, {CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK, CS42L42_SRCPL_VAL_MASK}, {CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK, CS42L42_VPMON_VAL_MASK}, {CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK, CS42L42_PLL_LOCK_VAL_MASK}, {CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK, CS42L42_TSRS_PLUG_VAL_MASK} }; static irqreturn_t cs42l42_irq_thread(int irq, void *data) { struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data; struct snd_soc_component *component = cs42l42->component; unsigned int stickies[12]; unsigned int masks[12]; unsigned int current_plug_status; unsigned int current_button_status; unsigned int i; /* Read sticky registers to clear interurpt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, &(stickies[i])); regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, &(masks[i])); stickies[i] = stickies[i] & (~masks[i]) & irq_params_table[i].mask; } /* Read tip sense status before handling type detect */ current_plug_status = (stickies[11] & (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> CS42L42_TS_PLUG_SHIFT; /* Read button sense status */ current_button_status = stickies[7] & (CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK); /* Check auto-detect status */ if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); dev_dbg(component->dev, "Auto detect done (%d)\n", cs42l42->hs_type); } } /* Check tip sense status */ if ((~masks[11]) & irq_params_table[11].mask) { switch (current_plug_status) { case CS42L42_TS_PLUG: if (cs42l42->plug_state != CS42L42_TS_PLUG) { cs42l42->plug_state = CS42L42_TS_PLUG; cs42l42_init_hs_type_detect(cs42l42); } break; case CS42L42_TS_UNPLUG: if (cs42l42->plug_state != CS42L42_TS_UNPLUG) { cs42l42->plug_state = CS42L42_TS_UNPLUG; cs42l42_cancel_hs_type_detect(cs42l42); dev_dbg(component->dev, "Unplug event\n"); } break; default: if (cs42l42->plug_state != CS42L42_TS_TRANS) cs42l42->plug_state = CS42L42_TS_TRANS; } } /* Check button detect status */ if ((~masks[7]) & irq_params_table[7].mask) { if (!(current_button_status & CS42L42_M_HSBIAS_HIZ_MASK)) { if (current_button_status & CS42L42_M_DETECT_TF_MASK) { dev_dbg(component->dev, "Button released\n"); } else if (current_button_status & CS42L42_M_DETECT_FT_MASK) { cs42l42_handle_button_press(cs42l42); } } } return IRQ_HANDLED; } static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) { regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK, CS42L42_ADC_OVFL_MASK, (1 << CS42L42_ADC_OVFL_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK, CS42L42_MIX_CHB_OVFL_MASK | CS42L42_MIX_CHA_OVFL_MASK | CS42L42_EQ_OVFL_MASK | CS42L42_EQ_BIQUAD_OVFL_MASK, (1 << CS42L42_MIX_CHB_OVFL_SHIFT) | (1 << CS42L42_MIX_CHA_OVFL_SHIFT) | (1 << CS42L42_EQ_OVFL_SHIFT) | (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK, CS42L42_SRC_ILK_MASK | CS42L42_SRC_OLK_MASK | CS42L42_SRC_IUNLK_MASK | CS42L42_SRC_OUNLK_MASK, (1 << CS42L42_SRC_ILK_SHIFT) | (1 << CS42L42_SRC_OLK_SHIFT) | (1 << CS42L42_SRC_IUNLK_SHIFT) | (1 << CS42L42_SRC_OUNLK_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK, CS42L42_ASPRX_NOLRCK_MASK | CS42L42_ASPRX_EARLY_MASK | CS42L42_ASPRX_LATE_MASK | CS42L42_ASPRX_ERROR_MASK | CS42L42_ASPRX_OVLD_MASK, (1 << CS42L42_ASPRX_NOLRCK_SHIFT) | (1 << CS42L42_ASPRX_EARLY_SHIFT) | (1 << CS42L42_ASPRX_LATE_SHIFT) | (1 << CS42L42_ASPRX_ERROR_SHIFT) | (1 << CS42L42_ASPRX_OVLD_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK, CS42L42_ASPTX_NOLRCK_MASK | CS42L42_ASPTX_EARLY_MASK | CS42L42_ASPTX_LATE_MASK | CS42L42_ASPTX_SMERROR_MASK, (1 << CS42L42_ASPTX_NOLRCK_SHIFT) | (1 << CS42L42_ASPTX_EARLY_SHIFT) | (1 << CS42L42_ASPTX_LATE_SHIFT) | (1 << CS42L42_ASPTX_SMERROR_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, CS42L42_PDN_DONE_MASK | CS42L42_HSDET_AUTO_DONE_MASK, (1 << CS42L42_PDN_DONE_SHIFT) | (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK, CS42L42_SRCPL_ADC_LK_MASK | CS42L42_SRCPL_DAC_LK_MASK | CS42L42_SRCPL_ADC_UNLK_MASK | CS42L42_SRCPL_DAC_UNLK_MASK, (1 << CS42L42_SRCPL_ADC_LK_SHIFT) | (1 << CS42L42_SRCPL_DAC_LK_SHIFT) | (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) | (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK, CS42L42_TIP_SENSE_UNPLUG_MASK | CS42L42_TIP_SENSE_PLUG_MASK | CS42L42_HSBIAS_SENSE_MASK, (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) | (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) | (1 << CS42L42_HSBIAS_SENSE_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, CS42L42_M_DETECT_TF_MASK | CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK | CS42L42_M_SHORT_RLS_MASK | CS42L42_M_SHORT_DET_MASK, (1 << CS42L42_M_DETECT_TF_SHIFT) | (1 << CS42L42_M_DETECT_FT_SHIFT) | (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK, CS42L42_VPMON_MASK, (1 << CS42L42_VPMON_SHIFT)); regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK, CS42L42_PLL_LOCK_MASK, (1 << CS42L42_PLL_LOCK_SHIFT)); 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)); } static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) { unsigned int reg; cs42l42->hs_type = CS42L42_PLUG_INVALID; /* Latch analog controls to VP power domain */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | CS42L42_EVENT_STAT_SEL_MASK | CS42L42_HS_DET_LEVEL_MASK, (1 << CS42L42_LATCH_TO_VP_SHIFT) | (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); /* Remove ground noise-suppression clamps */ regmap_update_bits(cs42l42->regmap, CS42L42_HS_CLAMP_DISABLE, CS42L42_HS_CLAMP_DISABLE_MASK, (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)); /* Enable the tip sense circuit */ regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL, CS42L42_TIP_SENSE_CTRL_MASK | CS42L42_TIP_SENSE_INV_MASK | CS42L42_TIP_SENSE_DEBOUNCE_MASK, (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) | (0 << CS42L42_TIP_SENSE_INV_SHIFT) | (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)); /* Save the initial status of the tip sense */ regmap_read(cs42l42->regmap, CS42L42_TSRS_PLUG_STATUS, ®); cs42l42->plug_state = (((char) reg) & (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> CS42L42_TS_PLUG_SHIFT; } static const unsigned int threshold_defaults[] = { CS42L42_HS_DET_LEVEL_15, CS42L42_HS_DET_LEVEL_8, CS42L42_HS_DET_LEVEL_4, CS42L42_HS_DET_LEVEL_1 }; static int cs42l42_handle_device_data(struct i2c_client *i2c_client, struct cs42l42_private *cs42l42) { struct device_node *np = i2c_client->dev.of_node; unsigned int val; unsigned int thresholds[CS42L42_NUM_BIASES]; int ret; int i; ret = of_property_read_u32(np, "cirrus,ts-inv", &val); if (!ret) { switch (val) { case CS42L42_TS_INV_EN: case CS42L42_TS_INV_DIS: cs42l42->ts_inv = val; break; default: dev_err(&i2c_client->dev, "Wrong cirrus,ts-inv DT value %d\n", val); cs42l42->ts_inv = CS42L42_TS_INV_DIS; } } else { cs42l42->ts_inv = CS42L42_TS_INV_DIS; } regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, CS42L42_TS_INV_MASK, (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT)); ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val); if (!ret) { switch (val) { case CS42L42_TS_DBNCE_0: case CS42L42_TS_DBNCE_125: case CS42L42_TS_DBNCE_250: case CS42L42_TS_DBNCE_500: case CS42L42_TS_DBNCE_750: case CS42L42_TS_DBNCE_1000: case CS42L42_TS_DBNCE_1250: case CS42L42_TS_DBNCE_1500: cs42l42->ts_dbnc_rise = val; break; default: dev_err(&i2c_client->dev, "Wrong cirrus,ts-dbnc-rise DT value %d\n", val); cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; } } else { cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; } regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, CS42L42_TS_RISE_DBNCE_TIME_MASK, (cs42l42->ts_dbnc_rise << CS42L42_TS_RISE_DBNCE_TIME_SHIFT)); ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val); if (!ret) { switch (val) { case CS42L42_TS_DBNCE_0: case CS42L42_TS_DBNCE_125: case CS42L42_TS_DBNCE_250: case CS42L42_TS_DBNCE_500: case CS42L42_TS_DBNCE_750: case CS42L42_TS_DBNCE_1000: case CS42L42_TS_DBNCE_1250: case CS42L42_TS_DBNCE_1500: cs42l42->ts_dbnc_fall = val; break; default: dev_err(&i2c_client->dev, "Wrong cirrus,ts-dbnc-fall DT value %d\n", val); cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; } } else { cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; } regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, CS42L42_TS_FALL_DBNCE_TIME_MASK, (cs42l42->ts_dbnc_fall << CS42L42_TS_FALL_DBNCE_TIME_SHIFT)); ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val); if (!ret) { if (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX) cs42l42->btn_det_init_dbnce = val; else { dev_err(&i2c_client->dev, "Wrong cirrus,btn-det-init-dbnce DT value %d\n", val); cs42l42->btn_det_init_dbnce = CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; } } else { cs42l42->btn_det_init_dbnce = CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; } ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val); if (!ret) { if (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX) cs42l42->btn_det_event_dbnce = val; else { dev_err(&i2c_client->dev, "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); cs42l42->btn_det_event_dbnce = CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; } } else { cs42l42->btn_det_event_dbnce = CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; } ret = of_property_read_u32_array(np, "cirrus,bias-lvls", (u32 *)thresholds, CS42L42_NUM_BIASES); if (!ret) { for (i = 0; i < CS42L42_NUM_BIASES; i++) { if (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX) cs42l42->bias_thresholds[i] = thresholds[i]; else { dev_err(&i2c_client->dev, "Wrong cirrus,bias-lvls[%d] DT value %d\n", i, thresholds[i]); cs42l42->bias_thresholds[i] = threshold_defaults[i]; } } } else { for (i = 0; i < CS42L42_NUM_BIASES; i++) cs42l42->bias_thresholds[i] = threshold_defaults[i]; } ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val); if (!ret) { switch (val) { case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL: cs42l42->hs_bias_ramp_rate = val; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0; break; case CS42L42_HSBIAS_RAMP_FAST: cs42l42->hs_bias_ramp_rate = val; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1; break; case CS42L42_HSBIAS_RAMP_SLOW: cs42l42->hs_bias_ramp_rate = val; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; break; case CS42L42_HSBIAS_RAMP_SLOWEST: cs42l42->hs_bias_ramp_rate = val; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3; break; default: dev_err(&i2c_client->dev, "Wrong cirrus,hs-bias-ramp-rate DT value %d\n", val); cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; } } else { cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; } regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL, CS42L42_HSBIAS_RAMP_MASK, (cs42l42->hs_bias_ramp_rate << CS42L42_HSBIAS_RAMP_SHIFT)); return 0; } static int cs42l42_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l42_private *cs42l42; int ret, i; unsigned int devid = 0; unsigned int reg; cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), GFP_KERNEL); if (!cs42l42) return -ENOMEM; i2c_set_clientdata(i2c_client, cs42l42); cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); if (IS_ERR(cs42l42->regmap)) { ret = PTR_ERR(cs42l42->regmap); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); return ret; } for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) cs42l42->supplies[i].supply = cs42l42_supply_names[i]; ret = devm_regulator_bulk_get(&i2c_client->dev, ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { dev_err(&i2c_client->dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { dev_err(&i2c_client->dev, "Failed to enable supplies: %d\n", ret); return ret; } /* Reset the Device */ cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs42l42->reset_gpio)) { ret = PTR_ERR(cs42l42->reset_gpio); goto err_disable; } if (cs42l42->reset_gpio) { dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); } usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); /* Request IRQ */ ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); if (ret != 0) dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); /* initialize codec */ ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®); devid = (reg & 0xFF) << 12; ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®); devid |= (reg & 0xFF) << 4; ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®); devid |= (reg & 0xF0) >> 4; if (devid != CS42L42_CHIP_ID) { ret = -ENODEV; dev_err(&i2c_client->dev, "CS42L42 Device ID (%X). Expected %X\n", devid, CS42L42_CHIP_ID); goto err_disable; } ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); goto err_disable; } dev_info(&i2c_client->dev, "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); /* Power up the codec */ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, CS42L42_ASP_DAO_PDN_MASK | CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | CS42L42_EQ_PDN_MASK | CS42L42_HP_PDN_MASK | CS42L42_ADC_PDN_MASK | CS42L42_PDN_ALL_MASK, (1 << CS42L42_ASP_DAO_PDN_SHIFT) | (1 << CS42L42_ASP_DAI_PDN_SHIFT) | (1 << CS42L42_MIXER_PDN_SHIFT) | (1 << CS42L42_EQ_PDN_SHIFT) | (1 << CS42L42_HP_PDN_SHIFT) | (1 << CS42L42_ADC_PDN_SHIFT) | (0 << CS42L42_PDN_ALL_SHIFT)); if (i2c_client->dev.of_node) { ret = cs42l42_handle_device_data(i2c_client, cs42l42); if (ret != 0) goto err_disable; } /* Setup headset detection */ cs42l42_setup_hs_type_detect(cs42l42); /* Mask/Unmask Interrupts */ cs42l42_set_interrupt_masks(cs42l42); /* Register codec for machine driver */ ret = devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_cs42l42, &cs42l42_dai, 1); if (ret < 0) goto err_disable; return 0; err_disable: regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); return ret; } static int cs42l42_i2c_remove(struct i2c_client *i2c_client) { struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42); pm_runtime_suspend(&i2c_client->dev); pm_runtime_disable(&i2c_client->dev); return 0; } #ifdef CONFIG_PM static int cs42l42_runtime_suspend(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); regcache_cache_only(cs42l42->regmap, true); regcache_mark_dirty(cs42l42->regmap); /* Hold down reset */ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); /* remove power */ regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); return 0; } static int cs42l42_runtime_resume(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); int ret; /* Enable power */ 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_sync(cs42l42->regmap); return 0; } #endif static const struct dev_pm_ops cs42l42_runtime_pm = { SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume, NULL) }; static const struct of_device_id cs42l42_of_match[] = { { .compatible = "cirrus,cs42l42", }, {}, }; MODULE_DEVICE_TABLE(of, cs42l42_of_match); static const struct i2c_device_id cs42l42_id[] = { {"cs42l42", 0}, {} }; MODULE_DEVICE_TABLE(i2c, cs42l42_id); static struct i2c_driver cs42l42_i2c_driver = { .driver = { .name = "cs42l42", .pm = &cs42l42_runtime_pm, .of_match_table = cs42l42_of_match, }, .id_table = cs42l42_id, .probe = cs42l42_i2c_probe, .remove = cs42l42_i2c_remove, }; module_i2c_driver(cs42l42_i2c_driver); MODULE_DESCRIPTION("ASoC CS42L42 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>"); MODULE_LICENSE("GPL");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
You can’t perform that action at this time.