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
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
c5487b9
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
ak4375.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-jack.c
arizona.c
arizona.h
bd28623.c
bt-sco.c
cirrus_legacy.h
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
cs35l41-i2c.c
cs35l41-lib.c
cs35l41-spi.c
cs35l41.c
cs35l41.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
max98520.c
max98520.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-accdet.c
mt6359-accdet.h
mt6359.c
mt6359.h
mt6660.c
mt6660.h
nau8315.c
nau8540.c
nau8540.h
nau8810.c
nau8810.h
nau8821.c
nau8821.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
rk817_codec.c
rl6231.c
rl6231.h
rl6347a.c
rl6347a.h
rt1011.c
rt1011.h
rt1015.c
rt1015.h
rt1015p.c
rt1016.c
rt1016.h
rt1019.c
rt1019.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
rt5682s.c
rt5682s.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
rt9120.c
sdw-mockup.c
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
tfa989x.c
tlv320adc3xxx.c
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-i2c.c
tlv320aic3x-spi.c
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
wcd-mbhc-v2.c
wcd-mbhc-v2.h
wcd9335.c
wcd9335.h
wcd934x.c
wcd938x-sdw.c
wcd938x.c
wcd938x.h
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
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
virtio
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
/
cs4265.c
Copy path
Blame
Blame
Latest commit
History
History
664 lines (573 loc) · 17 KB
Breadcrumbs
linux
/
sound
/
soc
/
codecs
/
cs4265.c
Top
File metadata and controls
Code
Blame
664 lines (573 loc) · 17 KB
Raw
// SPDX-License-Identifier: GPL-2.0-only /* * cs4265.c -- CS4265 ALSA SoC audio driver * * Copyright 2014 Cirrus Logic, Inc. * * Author: Paul Handrigan <paul.handrigan@cirrus.com> */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/platform_device.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 "cs4265.h" struct cs4265_private { struct regmap *regmap; struct gpio_desc *reset_gpio; u8 format; u32 sysclk; }; static const struct reg_default cs4265_reg_defaults[] = { { CS4265_PWRCTL, 0x0F }, { CS4265_DAC_CTL, 0x08 }, { CS4265_ADC_CTL, 0x00 }, { CS4265_MCLK_FREQ, 0x00 }, { CS4265_SIG_SEL, 0x40 }, { CS4265_CHB_PGA_CTL, 0x00 }, { CS4265_CHA_PGA_CTL, 0x00 }, { CS4265_ADC_CTL2, 0x19 }, { CS4265_DAC_CHA_VOL, 0x00 }, { CS4265_DAC_CHB_VOL, 0x00 }, { CS4265_DAC_CTL2, 0xC0 }, { CS4265_SPDIF_CTL1, 0x00 }, { CS4265_SPDIF_CTL2, 0x00 }, { CS4265_INT_MASK, 0x00 }, { CS4265_STATUS_MODE_MSB, 0x00 }, { CS4265_STATUS_MODE_LSB, 0x00 }, }; static bool cs4265_readable_register(struct device *dev, unsigned int reg) { switch (reg) { case CS4265_CHIP_ID ... CS4265_MAX_REGISTER: return true; default: return false; } } static bool cs4265_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS4265_INT_STATUS: return true; default: return false; } } static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0); static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0); static const char * const digital_input_mux_text[] = { "SDIN1", "SDIN2" }; static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7, digital_input_mux_text); static const struct snd_kcontrol_new digital_input_mux = SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum); static const char * const mic_linein_text[] = { "MIC", "LINEIN" }; static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0, mic_linein_text); static const char * const cam_mode_text[] = { "One Byte", "Two Byte" }; static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5, cam_mode_text); static const char * const cam_mono_stereo_text[] = { "Stereo", "Mono" }; static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2, cam_mono_stereo_text); static const char * const mono_select_text[] = { "Channel A", "Channel B" }; static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0, mono_select_text); static const struct snd_kcontrol_new mic_linein_mux = SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum); static const struct snd_kcontrol_new loopback_ctl = SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0); static const struct snd_kcontrol_new spdif_switch = SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0); static const struct snd_kcontrol_new dac_switch = SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0); static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL, CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv), SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL, CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv), SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1, 1, 0), SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5, 1, 0), SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6, 1, 0), SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7, 1, 0), SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1, 1, 0), SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3, 1, 1), SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7, 1, 0), SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, 6, 1, 0), SOC_ENUM("C Data Access", cam_mode_enum), SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0), SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), }; static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINEINL"), SND_SOC_DAPM_INPUT("LINEINR"), SND_SOC_DAPM_INPUT("MICL"), SND_SOC_DAPM_INPUT("MICR"), SND_SOC_DAPM_AIF_OUT("DOUT", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux), SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1), SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3, 1, NULL, 0), SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &digital_input_mux), SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0, &loopback_ctl), SND_SOC_DAPM_SWITCH("SPDIF", CS4265_SPDIF_CTL2, 5, 1, &spdif_switch), SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1, &dac_switch), SND_SOC_DAPM_AIF_IN("DIN1", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0, CS4265_SPDIF_CTL2, 5, 1), SND_SOC_DAPM_OUTPUT("LINEOUTL"), SND_SOC_DAPM_OUTPUT("LINEOUTR"), }; static const struct snd_soc_dapm_route cs4265_audio_map[] = { {"DIN1", NULL, "DAI1 Playback"}, {"DIN2", NULL, "DAI2 Playback"}, {"SDIN1 Input Mixer", NULL, "DIN1"}, {"SDIN2 Input Mixer", NULL, "DIN2"}, {"Input Mux", "SDIN1", "SDIN1 Input Mixer"}, {"Input Mux", "SDIN2", "SDIN2 Input Mixer"}, {"DAC", "Switch", "Input Mux"}, {"SPDIF", "Switch", "Input Mux"}, {"LINEOUTL", NULL, "DAC"}, {"LINEOUTR", NULL, "DAC"}, {"SPDIFOUT", NULL, "SPDIF"}, {"Pre-amp MIC", NULL, "MICL"}, {"Pre-amp MIC", NULL, "MICR"}, {"ADC Mux", "MIC", "Pre-amp MIC"}, {"ADC Mux", "LINEIN", "LINEINL"}, {"ADC Mux", "LINEIN", "LINEINR"}, {"ADC", NULL, "ADC Mux"}, {"DOUT", NULL, "ADC"}, {"DAI1 Capture", NULL, "DOUT"}, {"DAI2 Capture", NULL, "DOUT"}, /* Loopback */ {"Loopback", "Switch", "ADC"}, {"DAC", NULL, "Loopback"}, }; struct cs4265_clk_para { u32 mclk; u32 rate; u8 fm_mode; /* values 1, 2, or 4 */ u8 mclkdiv; }; static const struct cs4265_clk_para clk_map_table[] = { /*32k*/ {8192000, 32000, 0, 0}, {12288000, 32000, 0, 1}, {16384000, 32000, 0, 2}, {24576000, 32000, 0, 3}, {32768000, 32000, 0, 4}, /*44.1k*/ {11289600, 44100, 0, 0}, {16934400, 44100, 0, 1}, {22579200, 44100, 0, 2}, {33868000, 44100, 0, 3}, {45158400, 44100, 0, 4}, /*48k*/ {12288000, 48000, 0, 0}, {18432000, 48000, 0, 1}, {24576000, 48000, 0, 2}, {36864000, 48000, 0, 3}, {49152000, 48000, 0, 4}, /*64k*/ {8192000, 64000, 1, 0}, {12288000, 64000, 1, 1}, {16934400, 64000, 1, 2}, {24576000, 64000, 1, 3}, {32768000, 64000, 1, 4}, /* 88.2k */ {11289600, 88200, 1, 0}, {16934400, 88200, 1, 1}, {22579200, 88200, 1, 2}, {33868000, 88200, 1, 3}, {45158400, 88200, 1, 4}, /* 96k */ {12288000, 96000, 1, 0}, {18432000, 96000, 1, 1}, {24576000, 96000, 1, 2}, {36864000, 96000, 1, 3}, {49152000, 96000, 1, 4}, /* 128k */ {8192000, 128000, 2, 0}, {12288000, 128000, 2, 1}, {16934400, 128000, 2, 2}, {24576000, 128000, 2, 3}, {32768000, 128000, 2, 4}, /* 176.4k */ {11289600, 176400, 2, 0}, {16934400, 176400, 2, 1}, {22579200, 176400, 2, 2}, {33868000, 176400, 2, 3}, {49152000, 176400, 2, 4}, /* 192k */ {12288000, 192000, 2, 0}, {18432000, 192000, 2, 1}, {24576000, 192000, 2, 2}, {36864000, 192000, 2, 3}, {49152000, 192000, 2, 4}, }; static int cs4265_get_clk_index(int mclk, int rate) { int i; for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { if (clk_map_table[i].rate == rate && clk_map_table[i].mclk == mclk) return i; } return -EINVAL; } static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_component *component = codec_dai->component; struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component); int i; if (clk_id != 0) { dev_err(component->dev, "Invalid clk_id %d\n", clk_id); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { if (clk_map_table[i].mclk == freq) { cs4265->sysclk = freq; return 0; } } cs4265->sysclk = 0; dev_err(component->dev, "Invalid freq parameter %d\n", freq); return -EINVAL; } static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component); u8 iface = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_MASTER, CS4265_ADC_MASTER); break; case SND_SOC_DAIFMT_CBS_CFS: snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_MASTER, 0); break; default: return -EINVAL; } /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: iface |= SND_SOC_DAIFMT_I2S; break; case SND_SOC_DAIFMT_RIGHT_J: iface |= SND_SOC_DAIFMT_RIGHT_J; break; case SND_SOC_DAIFMT_LEFT_J: iface |= SND_SOC_DAIFMT_LEFT_J; break; default: return -EINVAL; } cs4265->format = iface; return 0; } static int cs4265_mute(struct snd_soc_dai *dai, int mute, int direction) { struct snd_soc_component *component = dai->component; if (mute) { snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_MUTE, CS4265_DAC_CTL_MUTE); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_MUTE, CS4265_SPDIF_CTL2_MUTE); } else { snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_MUTE, 0); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_MUTE, 0); } return 0; } static int cs4265_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 cs4265_private *cs4265 = snd_soc_component_get_drvdata(component); int index; if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && ((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_RIGHT_J)) return -EINVAL; index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); if (index >= 0) { snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_FM, clk_map_table[index].fm_mode << 6); snd_soc_component_update_bits(component, CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_MASK, clk_map_table[index].mclkdiv << 4); } else { dev_err(component->dev, "can't get correct mclk\n"); return -EINVAL; } switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (1 << 4)); snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_DIF, (1 << 4)); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 6)); break; case SND_SOC_DAIFMT_RIGHT_J: if (params_width(params) == 16) { snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (2 << 4)); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (2 << 6)); } else { snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (3 << 4)); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (3 << 6)); } break; case SND_SOC_DAIFMT_LEFT_J: snd_soc_component_update_bits(component, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, 0); snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_DIF, 0); snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, 0); break; default: return -EINVAL; } return 0; } static int cs4265_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: snd_soc_component_update_bits(component, CS4265_PWRCTL, CS4265_PWRCTL_PDN, 0); break; case SND_SOC_BIAS_STANDBY: snd_soc_component_update_bits(component, CS4265_PWRCTL, CS4265_PWRCTL_PDN, CS4265_PWRCTL_PDN); break; case SND_SOC_BIAS_OFF: snd_soc_component_update_bits(component, CS4265_PWRCTL, CS4265_PWRCTL_PDN, CS4265_PWRCTL_PDN); break; } return 0; } #define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) #define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static const struct snd_soc_dai_ops cs4265_ops = { .hw_params = cs4265_pcm_hw_params, .mute_stream = cs4265_mute, .set_fmt = cs4265_set_fmt, .set_sysclk = cs4265_set_sysclk, .no_capture_mute = 1, }; static struct snd_soc_dai_driver cs4265_dai[] = { { .name = "cs4265-dai1", .playback = { .stream_name = "DAI1 Playback", .channels_min = 1, .channels_max = 2, .rates = CS4265_RATES, .formats = CS4265_FORMATS, }, .capture = { .stream_name = "DAI1 Capture", .channels_min = 1, .channels_max = 2, .rates = CS4265_RATES, .formats = CS4265_FORMATS, }, .ops = &cs4265_ops, }, { .name = "cs4265-dai2", .playback = { .stream_name = "DAI2 Playback", .channels_min = 1, .channels_max = 2, .rates = CS4265_RATES, .formats = CS4265_FORMATS, }, .capture = { .stream_name = "DAI2 Capture", .channels_min = 1, .channels_max = 2, .rates = CS4265_RATES, .formats = CS4265_FORMATS, }, .ops = &cs4265_ops, }, }; static const struct snd_soc_component_driver soc_component_cs4265 = { .set_bias_level = cs4265_set_bias_level, .controls = cs4265_snd_controls, .num_controls = ARRAY_SIZE(cs4265_snd_controls), .dapm_widgets = cs4265_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets), .dapm_routes = cs4265_audio_map, .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map), .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, .non_legacy_dai_naming = 1, }; static const struct regmap_config cs4265_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = CS4265_MAX_REGISTER, .reg_defaults = cs4265_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults), .readable_reg = cs4265_readable_register, .volatile_reg = cs4265_volatile_register, .cache_type = REGCACHE_RBTREE, }; static int cs4265_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs4265_private *cs4265; int ret; unsigned int devid = 0; unsigned int reg; cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private), GFP_KERNEL); if (cs4265 == NULL) return -ENOMEM; cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); if (IS_ERR(cs4265->regmap)) { ret = PTR_ERR(cs4265->regmap); dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); return ret; } cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs4265->reset_gpio)) return PTR_ERR(cs4265->reset_gpio); if (cs4265->reset_gpio) { mdelay(1); gpiod_set_value_cansleep(cs4265->reset_gpio, 1); } i2c_set_clientdata(i2c_client, cs4265); ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, ®); if (ret) { dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); return ret; } devid = reg & CS4265_CHIP_ID_MASK; if (devid != CS4265_CHIP_ID_VAL) { ret = -ENODEV; dev_err(&i2c_client->dev, "CS4265 Part Number ID: 0x%x Expected: 0x%x\n", devid >> 4, CS4265_CHIP_ID_VAL >> 4); return ret; } dev_info(&i2c_client->dev, "CS4265 Version %x\n", reg & CS4265_REV_ID_MASK); regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F); return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_cs4265, cs4265_dai, 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", }, { } }; MODULE_DEVICE_TABLE(of, cs4265_of_match); static const struct i2c_device_id cs4265_id[] = { { "cs4265", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, cs4265_id); static struct i2c_driver cs4265_i2c_driver = { .driver = { .name = "cs4265", .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, .probe = cs4265_i2c_probe, .remove = cs4265_i2c_remove, }; module_i2c_driver(cs4265_i2c_driver); MODULE_DESCRIPTION("ASoC CS4265 driver"); MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@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
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
You can’t perform that action at this time.