mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 23:28:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
1438
sound/soc/codecs/88pm860x-codec.c
Normal file
1438
sound/soc/codecs/88pm860x-codec.c
Normal file
File diff suppressed because it is too large
Load diff
96
sound/soc/codecs/88pm860x-codec.h
Normal file
96
sound/soc/codecs/88pm860x-codec.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
|
||||
*
|
||||
* Copyright 2010 Marvell International Ltd.
|
||||
* Haojian Zhuang <haojian.zhuang@marvell.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __88PM860X_H
|
||||
#define __88PM860X_H
|
||||
|
||||
#define PM860X_PCM_IFACE_1 0xb0
|
||||
#define PM860X_PCM_IFACE_2 0xb1
|
||||
#define PM860X_PCM_IFACE_3 0xb2
|
||||
#define PM860X_PCM_RATE 0xb3
|
||||
#define PM860X_EC_PATH 0xb4
|
||||
#define PM860X_SIDETONE_L_GAIN 0xb5
|
||||
#define PM860X_SIDETONE_R_GAIN 0xb6
|
||||
#define PM860X_SIDETONE_SHIFT 0xb7
|
||||
#define PM860X_ADC_OFFSET_1 0xb8
|
||||
#define PM860X_ADC_OFFSET_2 0xb9
|
||||
#define PM860X_DMIC_DELAY 0xba
|
||||
|
||||
#define PM860X_I2S_IFACE_1 0xbb
|
||||
#define PM860X_I2S_IFACE_2 0xbc
|
||||
#define PM860X_I2S_IFACE_3 0xbd
|
||||
#define PM860X_I2S_IFACE_4 0xbe
|
||||
#define PM860X_EQUALIZER_N0_1 0xbf
|
||||
#define PM860X_EQUALIZER_N0_2 0xc0
|
||||
#define PM860X_EQUALIZER_N1_1 0xc1
|
||||
#define PM860X_EQUALIZER_N1_2 0xc2
|
||||
#define PM860X_EQUALIZER_D1_1 0xc3
|
||||
#define PM860X_EQUALIZER_D1_2 0xc4
|
||||
#define PM860X_LOFI_GAIN_LEFT 0xc5
|
||||
#define PM860X_LOFI_GAIN_RIGHT 0xc6
|
||||
#define PM860X_HIFIL_GAIN_LEFT 0xc7
|
||||
#define PM860X_HIFIL_GAIN_RIGHT 0xc8
|
||||
#define PM860X_HIFIR_GAIN_LEFT 0xc9
|
||||
#define PM860X_HIFIR_GAIN_RIGHT 0xca
|
||||
#define PM860X_DAC_OFFSET 0xcb
|
||||
#define PM860X_OFFSET_LEFT_1 0xcc
|
||||
#define PM860X_OFFSET_LEFT_2 0xcd
|
||||
#define PM860X_OFFSET_RIGHT_1 0xce
|
||||
#define PM860X_OFFSET_RIGHT_2 0xcf
|
||||
#define PM860X_ADC_ANA_1 0xd0
|
||||
#define PM860X_ADC_ANA_2 0xd1
|
||||
#define PM860X_ADC_ANA_3 0xd2
|
||||
#define PM860X_ADC_ANA_4 0xd3
|
||||
#define PM860X_ANA_TO_ANA 0xd4
|
||||
#define PM860X_HS1_CTRL 0xd5
|
||||
#define PM860X_HS2_CTRL 0xd6
|
||||
#define PM860X_LO1_CTRL 0xd7
|
||||
#define PM860X_LO2_CTRL 0xd8
|
||||
#define PM860X_EAR_CTRL_1 0xd9
|
||||
#define PM860X_EAR_CTRL_2 0xda
|
||||
#define PM860X_AUDIO_SUPPLIES_1 0xdb
|
||||
#define PM860X_AUDIO_SUPPLIES_2 0xdc
|
||||
#define PM860X_ADC_EN_1 0xdd
|
||||
#define PM860X_ADC_EN_2 0xde
|
||||
#define PM860X_DAC_EN_1 0xdf
|
||||
#define PM860X_DAC_EN_2 0xe1
|
||||
#define PM860X_AUDIO_CAL_1 0xe2
|
||||
#define PM860X_AUDIO_CAL_2 0xe3
|
||||
#define PM860X_AUDIO_CAL_3 0xe4
|
||||
#define PM860X_AUDIO_CAL_4 0xe5
|
||||
#define PM860X_AUDIO_CAL_5 0xe6
|
||||
#define PM860X_ANA_INPUT_SEL_1 0xe7
|
||||
#define PM860X_ANA_INPUT_SEL_2 0xe8
|
||||
|
||||
#define PM860X_PCM_IFACE_4 0xe9
|
||||
#define PM860X_I2S_IFACE_5 0xea
|
||||
|
||||
#define PM860X_SHORTS 0x3b
|
||||
#define PM860X_PLL_ADJ_1 0x3c
|
||||
#define PM860X_PLL_ADJ_2 0x3d
|
||||
|
||||
/* bits definition */
|
||||
#define PM860X_CLK_DIR_IN 0
|
||||
#define PM860X_CLK_DIR_OUT 1
|
||||
|
||||
#define PM860X_DET_HEADSET (1 << 0)
|
||||
#define PM860X_DET_MIC (1 << 1)
|
||||
#define PM860X_DET_HOOK (1 << 2)
|
||||
#define PM860X_SHORT_HEADSET (1 << 3)
|
||||
#define PM860X_SHORT_LINEOUT (1 << 4)
|
||||
#define PM860X_DET_MASK 0x1F
|
||||
|
||||
extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
|
||||
int, int, int, int);
|
||||
extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
|
||||
int);
|
||||
|
||||
#endif /* __88PM860X_H */
|
||||
836
sound/soc/codecs/Kconfig
Executable file
836
sound/soc/codecs/Kconfig
Executable file
|
|
@ -0,0 +1,836 @@
|
|||
# Helper to resolve issues with configs that have SPI enabled but I2C
|
||||
# modular, meaning we can't build the codec driver in with I2C support.
|
||||
# We use an ordered list of conditional defaults to pick the appropriate
|
||||
# setting - SPI can't be modular so that case doesn't need to be covered.
|
||||
config SND_SOC_I2C_AND_SPI
|
||||
tristate
|
||||
default m if I2C=m
|
||||
default y if I2C=y
|
||||
default y if SPI_MASTER=y
|
||||
|
||||
menu "CODEC drivers"
|
||||
|
||||
config SND_SOC_ALL_CODECS
|
||||
tristate "Build all ASoC CODEC drivers"
|
||||
depends on COMPILE_TEST
|
||||
select SND_SOC_88PM860X if MFD_88PM860X
|
||||
select SND_SOC_L3
|
||||
select SND_SOC_AB8500_CODEC if ABX500_CORE
|
||||
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD1836 if SPI_MASTER
|
||||
select SND_SOC_AD193X_SPI if SPI_MASTER
|
||||
select SND_SOC_AD193X_I2C if I2C
|
||||
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD73311
|
||||
select SND_SOC_ADAU1373 if I2C
|
||||
select SND_SOC_ADAU1761_I2C if I2C
|
||||
select SND_SOC_ADAU1761_SPI if SPI
|
||||
select SND_SOC_ADAU1781_I2C if I2C
|
||||
select SND_SOC_ADAU1781_SPI if SPI
|
||||
select SND_SOC_ADAV801 if SPI_MASTER
|
||||
select SND_SOC_ADAV803 if I2C
|
||||
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
||||
select SND_SOC_ADAU1977_I2C if I2C
|
||||
select SND_SOC_ADAU1701 if I2C
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
select SND_SOC_AK4535 if I2C
|
||||
select SND_SOC_AK4554
|
||||
select SND_SOC_AK4641 if I2C
|
||||
select SND_SOC_AK4642 if I2C
|
||||
select SND_SOC_AK4671 if I2C
|
||||
select SND_SOC_AK5386
|
||||
select SND_SOC_ALC5623 if I2C
|
||||
select SND_SOC_ALC5632 if I2C
|
||||
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
|
||||
select SND_SOC_CS35L32 if I2C
|
||||
select SND_SOC_CS42L51_I2C if I2C
|
||||
select SND_SOC_CS42L52 if I2C && INPUT
|
||||
select SND_SOC_CS42L56 if I2C && INPUT
|
||||
select SND_SOC_CS42L73 if I2C
|
||||
select SND_SOC_CS4265 if I2C
|
||||
select SND_SOC_CS4270 if I2C
|
||||
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CS42XX8_I2C if I2C
|
||||
select SND_SOC_LARGO if MFD_LARGO
|
||||
select SND_SOC_CX20442 if TTY
|
||||
select SND_SOC_DA7210 if I2C
|
||||
select SND_SOC_DA7213 if I2C
|
||||
select SND_SOC_DA732X if I2C
|
||||
select SND_SOC_DA9055 if I2C
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_BT_SCO
|
||||
select SND_SOC_ES8328_SPI if SPI_MASTER
|
||||
select SND_SOC_ES8328_I2C if I2C
|
||||
select SND_SOC_ISABELLE if I2C
|
||||
select SND_SOC_JZ4740_CODEC
|
||||
select SND_SOC_LM4857 if I2C
|
||||
select SND_SOC_LM49453 if I2C
|
||||
select SND_SOC_MAX98088 if I2C
|
||||
select SND_SOC_MAX98090 if I2C
|
||||
select SND_SOC_MAX98095 if I2C
|
||||
select SND_SOC_MAX9850 if I2C
|
||||
select SND_SOC_MAX9768 if I2C
|
||||
select SND_SOC_MAX9877 if I2C
|
||||
select SND_SOC_MC13783 if MFD_MC13XXX
|
||||
select SND_SOC_ML26124 if I2C
|
||||
select SND_SOC_HDMI_CODEC
|
||||
select SND_SOC_PCM1681 if I2C
|
||||
select SND_SOC_PCM1792A if SPI_MASTER
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_PCM512x_I2C if I2C
|
||||
select SND_SOC_PCM512x_SPI if SPI_MASTER
|
||||
select SND_SOC_RT286 if I2C
|
||||
select SND_SOC_RT5631 if I2C
|
||||
select SND_SOC_RT5640 if I2C
|
||||
select SND_SOC_RT5645 if I2C
|
||||
select SND_SOC_RT5651 if I2C
|
||||
select SND_SOC_RT5670 if I2C
|
||||
select SND_SOC_RT5677 if I2C
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
select SND_SOC_SI476X if MFD_SI476X_CORE
|
||||
select SND_SOC_SIRF_AUDIO_CODEC
|
||||
select SND_SOC_SN95031 if INTEL_SCU_IPC
|
||||
select SND_SOC_SPDIF
|
||||
select SND_SOC_SSM2518 if I2C
|
||||
select SND_SOC_SSM2602_SPI if SPI_MASTER
|
||||
select SND_SOC_SSM2602_I2C if I2C
|
||||
select SND_SOC_SSM4567 if I2C
|
||||
select SND_SOC_STA32X if I2C
|
||||
select SND_SOC_STA350 if I2C
|
||||
select SND_SOC_STA529 if I2C
|
||||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TAS2552 if I2C
|
||||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TLV320AIC23_I2C if I2C
|
||||
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC26 if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC31XX if I2C
|
||||
select SND_SOC_TLV320AIC32X4 if I2C
|
||||
select SND_SOC_TLV320AIC3X if I2C
|
||||
select SND_SOC_TPA6130A2 if I2C
|
||||
select SND_SOC_TLV320DAC33 if I2C
|
||||
select SND_SOC_TWL4030 if TWL4030_CORE
|
||||
select SND_SOC_TWL6040 if TWL6040_CORE
|
||||
select SND_SOC_UDA134X
|
||||
select SND_SOC_UDA1380 if I2C
|
||||
select SND_SOC_WL1273 if MFD_WL1273_CORE
|
||||
select SND_SOC_WM0010 if SPI_MASTER
|
||||
select SND_SOC_WM1250_EV1 if I2C
|
||||
select SND_SOC_WM2000 if I2C
|
||||
select SND_SOC_WM2200 if I2C
|
||||
select SND_SOC_WM5100 if I2C
|
||||
select SND_SOC_WM5102 if MFD_WM5102
|
||||
select SND_SOC_WM5110 if MFD_WM5110
|
||||
select SND_SOC_WM8350 if MFD_WM8350
|
||||
select SND_SOC_WM8400 if MFD_WM8400
|
||||
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8523 if I2C
|
||||
select SND_SOC_WM8580 if I2C
|
||||
select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8727
|
||||
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8770 if SPI_MASTER
|
||||
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8782
|
||||
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8900 if I2C
|
||||
select SND_SOC_WM8903 if I2C
|
||||
select SND_SOC_WM8904 if I2C
|
||||
select SND_SOC_WM8940 if I2C
|
||||
select SND_SOC_WM8955 if I2C
|
||||
select SND_SOC_WM8960 if I2C
|
||||
select SND_SOC_WM8961 if I2C
|
||||
select SND_SOC_WM8962 if I2C && INPUT
|
||||
select SND_SOC_WM8971 if I2C
|
||||
select SND_SOC_WM8974 if I2C
|
||||
select SND_SOC_WM8978 if I2C
|
||||
select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8990 if I2C
|
||||
select SND_SOC_WM8991 if I2C
|
||||
select SND_SOC_WM8993 if I2C
|
||||
select SND_SOC_WM8994 if MFD_WM8994
|
||||
select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8996 if I2C
|
||||
select SND_SOC_WM8997 if MFD_WM8997
|
||||
select SND_SOC_WM9081 if I2C
|
||||
select SND_SOC_WM9090 if I2C
|
||||
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_WM9713 if SND_SOC_AC97_BUS
|
||||
help
|
||||
Normally ASoC codec drivers are only built if a machine driver which
|
||||
uses them is also built since they are only usable with a machine
|
||||
driver. Selecting this option will allow these drivers to be built
|
||||
without an explicit machine driver for test and development purposes.
|
||||
|
||||
Support for the bus types used to access the codecs to be built must
|
||||
be selected separately.
|
||||
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_88PM860X
|
||||
tristate
|
||||
|
||||
config SND_SOC_ARIZONA
|
||||
tristate
|
||||
default y if SND_SOC_WM5102=y
|
||||
default y if SND_SOC_WM5110=y
|
||||
default y if SND_SOC_WM8997=y
|
||||
default y if SND_SOC_LARGO=y
|
||||
default m if SND_SOC_WM5102=m
|
||||
default m if SND_SOC_WM5110=m
|
||||
default m if SND_SOC_WM8997=m
|
||||
default m if SND_SOC_LARGO=m
|
||||
|
||||
config SND_SOC_WM_HUBS
|
||||
tristate
|
||||
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
|
||||
default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
|
||||
|
||||
config SND_SOC_WM_ADSP
|
||||
tristate
|
||||
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_LARGO=y
|
||||
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_LARGO=m
|
||||
|
||||
config SND_SOC_AB8500_CODEC
|
||||
tristate
|
||||
|
||||
config SND_SOC_AC97_CODEC
|
||||
tristate
|
||||
select SND_AC97_CODEC
|
||||
|
||||
config SND_SOC_AD1836
|
||||
tristate
|
||||
|
||||
config SND_SOC_AD193X
|
||||
tristate
|
||||
|
||||
config SND_SOC_AD193X_SPI
|
||||
tristate
|
||||
select SND_SOC_AD193X
|
||||
|
||||
config SND_SOC_AD193X_I2C
|
||||
tristate
|
||||
select SND_SOC_AD193X
|
||||
|
||||
config SND_SOC_AD1980
|
||||
tristate
|
||||
|
||||
config SND_SOC_AD73311
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1701
|
||||
tristate "Analog Devices ADAU1701 CODEC"
|
||||
depends on I2C
|
||||
select SND_SOC_SIGMADSP_I2C
|
||||
|
||||
config SND_SOC_ADAU17X1
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP_REGMAP
|
||||
|
||||
config SND_SOC_ADAU1761
|
||||
tristate
|
||||
select SND_SOC_ADAU17X1
|
||||
|
||||
config SND_SOC_ADAU1761_I2C
|
||||
tristate
|
||||
select SND_SOC_ADAU1761
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU1761_SPI
|
||||
tristate
|
||||
select SND_SOC_ADAU1761
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1781
|
||||
select SND_SOC_ADAU17X1
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1781_I2C
|
||||
tristate
|
||||
select SND_SOC_ADAU1781
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU1781_SPI
|
||||
tristate
|
||||
select SND_SOC_ADAU1781
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1977
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1977_SPI
|
||||
tristate
|
||||
select SND_SOC_ADAU1977
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1977_I2C
|
||||
tristate
|
||||
select SND_SOC_ADAU1977
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAV80X
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAV801
|
||||
tristate
|
||||
select SND_SOC_ADAV80X
|
||||
|
||||
config SND_SOC_ADAV803
|
||||
tristate
|
||||
select SND_SOC_ADAV80X
|
||||
|
||||
config SND_SOC_ADS117X
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK4104
|
||||
tristate "AKM AK4104 CODEC"
|
||||
depends on SPI_MASTER
|
||||
|
||||
config SND_SOC_AK4535
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK4554
|
||||
tristate "AKM AK4554 CODEC"
|
||||
|
||||
config SND_SOC_AK4641
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK4642
|
||||
tristate "AKM AK4642 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_AK4671
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK5386
|
||||
tristate "AKM AK5638 CODEC"
|
||||
|
||||
config SND_SOC_ALC5623
|
||||
tristate "Realtek ALC5623 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_ALC5632
|
||||
tristate
|
||||
|
||||
config SND_SOC_CQ0093VC
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS35L32
|
||||
tristate "Cirrus Logic CS35L32 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS42L51
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS42L51_I2C
|
||||
tristate
|
||||
select SND_SOC_CS42L51
|
||||
|
||||
config SND_SOC_CS42L52
|
||||
tristate "Cirrus Logic CS42L52 CODEC"
|
||||
depends on I2C && INPUT
|
||||
|
||||
config SND_SOC_CS42L56
|
||||
tristate "Cirrus Logic CS42L56 CODEC"
|
||||
depends on I2C && INPUT
|
||||
|
||||
config SND_SOC_CS42L73
|
||||
tristate "Cirrus Logic CS42L73 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS4265
|
||||
tristate "Cirrus Logic CS4265 CODEC"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
|
||||
# Cirrus Logic CS4270 Codec
|
||||
config SND_SOC_CS4270
|
||||
tristate "Cirrus Logic CS4270 CODEC"
|
||||
depends on I2C
|
||||
|
||||
# Cirrus Logic CS4270 Codec VD = 3.3V Errata
|
||||
# Select if you are affected by the errata where the part will not function
|
||||
# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
|
||||
# not select any sample rates that require MCLK to be divided by 1.5.
|
||||
config SND_SOC_CS4270_VD33_ERRATA
|
||||
bool
|
||||
depends on SND_SOC_CS4270
|
||||
|
||||
config SND_SOC_CS4271
|
||||
tristate "Cirrus Logic CS4271 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_CS42XX8
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS42XX8_I2C
|
||||
tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
|
||||
depends on I2C
|
||||
select SND_SOC_CS42XX8
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_LARGO
|
||||
tristate
|
||||
|
||||
config SND_SOC_CX20442
|
||||
tristate
|
||||
depends on TTY
|
||||
|
||||
config SND_SOC_COD3026X
|
||||
tristate
|
||||
default n
|
||||
|
||||
config SND_SOC_COD9002X
|
||||
tristate
|
||||
default y
|
||||
|
||||
config SND_SOC_JZ4740_CODEC
|
||||
select REGMAP_MMIO
|
||||
tristate
|
||||
|
||||
config SND_SOC_L3
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA7210
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA7213
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA732X
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA9055
|
||||
tristate
|
||||
|
||||
config SND_SOC_BT_SCO
|
||||
tristate
|
||||
|
||||
config SND_SOC_DMIC
|
||||
tristate
|
||||
|
||||
config SND_SOC_HDMI_CODEC
|
||||
tristate "HDMI stub CODEC"
|
||||
|
||||
config SND_SOC_ES8328
|
||||
tristate "Everest Semi ES8328 CODEC"
|
||||
|
||||
config SND_SOC_ES8328_I2C
|
||||
tristate
|
||||
select SND_SOC_ES8328
|
||||
|
||||
config SND_SOC_ES8328_SPI
|
||||
tristate
|
||||
select SND_SOC_ES8328
|
||||
|
||||
config SND_SOC_ISABELLE
|
||||
tristate
|
||||
|
||||
config SND_SOC_LM49453
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98088
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98090
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98095
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX9850
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM1681
|
||||
tristate "Texas Instruments PCM1681 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_PCM1792A
|
||||
tristate "Texas Instruments PCM1792A CODEC"
|
||||
depends on SPI_MASTER
|
||||
|
||||
config SND_SOC_PCM3008
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM512x
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM512x_I2C
|
||||
tristate "Texas Instruments PCM512x CODECs - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_PCM512x
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_PCM512x_SPI
|
||||
tristate "Texas Instruments PCM512x CODECs - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_PCM512x
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_RL6231
|
||||
tristate
|
||||
default y if SND_SOC_RT5640=y
|
||||
default y if SND_SOC_RT5645=y
|
||||
default y if SND_SOC_RT5651=y
|
||||
default y if SND_SOC_RT5670=y
|
||||
default y if SND_SOC_RT5677=y
|
||||
default m if SND_SOC_RT5640=m
|
||||
default m if SND_SOC_RT5645=m
|
||||
default m if SND_SOC_RT5651=m
|
||||
default m if SND_SOC_RT5670=m
|
||||
default m if SND_SOC_RT5677=m
|
||||
|
||||
config SND_SOC_RT286
|
||||
tristate
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_RT5631
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5640
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5645
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5651
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5670
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5677
|
||||
tristate
|
||||
|
||||
#Freescale sgtl5000 codec
|
||||
config SND_SOC_SGTL5000
|
||||
tristate "Freescale SGTL5000 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_SI476X
|
||||
tristate
|
||||
|
||||
config SND_SOC_SIGMADSP
|
||||
tristate
|
||||
select CRC32
|
||||
|
||||
config SND_SOC_SIGMADSP_I2C
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP
|
||||
|
||||
config SND_SOC_SIGMADSP_REGMAP
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP
|
||||
|
||||
config SND_SOC_SIRF_AUDIO_CODEC
|
||||
tristate "SiRF SoC internal audio codec"
|
||||
select REGMAP_MMIO
|
||||
|
||||
config SND_SOC_SN95031
|
||||
tristate
|
||||
|
||||
config SND_SOC_SPDIF
|
||||
tristate "S/PDIF CODEC"
|
||||
|
||||
config SND_SOC_EXYNOS_AUDMIXER
|
||||
tristate
|
||||
select REGMAP_MMIO
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_SSM2518
|
||||
tristate
|
||||
|
||||
config SND_SOC_SSM2602
|
||||
tristate
|
||||
|
||||
config SND_SOC_SSM2602_SPI
|
||||
tristate "Analog Devices SSM2602 CODEC - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_SSM2602
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_SSM2602_I2C
|
||||
tristate "Analog Devices SSM2602 CODEC - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_SSM2602
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_SSM4567
|
||||
tristate "Analog Devices ssm4567 amplifier driver support"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_STA32X
|
||||
tristate
|
||||
|
||||
config SND_SOC_STA350
|
||||
tristate "STA350 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_STA529
|
||||
tristate
|
||||
|
||||
config SND_SOC_STAC9766
|
||||
tristate
|
||||
|
||||
config SND_SOC_TAS2552
|
||||
tristate "Texas Instruments TAS2552 Mono Audio amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TAS5086
|
||||
tristate "Texas Instruments TAS5086 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TLV320AIC23
|
||||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC23_I2C
|
||||
tristate
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC23_SPI
|
||||
tristate
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC26
|
||||
tristate
|
||||
depends on SPI
|
||||
|
||||
config SND_SOC_TLV320AIC31XX
|
||||
tristate "Texas Instruments TLV320AIC31xx CODECs"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_TLV320AIC32X4
|
||||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC3X
|
||||
tristate "Texas Instruments TLV320AIC3x CODECs"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TLV320DAC33
|
||||
tristate
|
||||
|
||||
config SND_SOC_TWL4030
|
||||
select MFD_TWL4030_AUDIO
|
||||
tristate
|
||||
|
||||
config SND_SOC_TWL6040
|
||||
tristate
|
||||
|
||||
config SND_SOC_UDA134X
|
||||
tristate
|
||||
|
||||
config SND_SOC_UDA1380
|
||||
tristate
|
||||
|
||||
config SND_SOC_WL1273
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM0010
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM1250_EV1
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM2000
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM2200
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM5100
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM5102
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM5110
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8350
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8400
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8510
|
||||
tristate "Wolfson Microelectronics WM8510 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8523
|
||||
tristate "Wolfson Microelectronics WM8523 DAC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8580
|
||||
tristate "Wolfson Microelectronics WM8523 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8711
|
||||
tristate "Wolfson Microelectronics WM8711 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8727
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8728
|
||||
tristate "Wolfson Microelectronics WM8728 DAC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8731
|
||||
tristate "Wolfson Microelectronics WM8731 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8737
|
||||
tristate "Wolfson Microelectronics WM8737 ADC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8741
|
||||
tristate "Wolfson Microelectronics WM8737 DAC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8750
|
||||
tristate "Wolfson Microelectronics WM8750 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8753
|
||||
tristate "Wolfson Microelectronics WM8753 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8770
|
||||
tristate "Wolfson Microelectronics WM8770 CODEC"
|
||||
depends on SPI_MASTER
|
||||
|
||||
config SND_SOC_WM8776
|
||||
tristate "Wolfson Microelectronics WM8776 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8782
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8804
|
||||
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8900
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8903
|
||||
tristate "Wolfson Microelectronics WM8903 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8904
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8940
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8955
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8960
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8961
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8962
|
||||
tristate "Wolfson Microelectronics WM8962 CODEC"
|
||||
depends on I2C && INPUT
|
||||
|
||||
config SND_SOC_WM8971
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8974
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8978
|
||||
tristate "Wolfson Microelectronics WM8978 codec"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8983
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8985
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8988
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8990
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8991
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8993
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8994
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8995
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8996
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8997
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9081
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9090
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9705
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9712
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9713
|
||||
tristate
|
||||
|
||||
config SND_SOC_DUMMY_CODEC
|
||||
tristate
|
||||
|
||||
# Amp
|
||||
config SND_SOC_LM4857
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX9768
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX9877
|
||||
tristate
|
||||
|
||||
config SND_SOC_MC13783
|
||||
tristate
|
||||
|
||||
config SND_SOC_ML26124
|
||||
tristate
|
||||
|
||||
config SND_SOC_TPA6130A2
|
||||
tristate "Texas Instruments TPA6130A2 headphone amplifier"
|
||||
depends on I2C
|
||||
|
||||
endmenu
|
||||
355
sound/soc/codecs/Makefile
Executable file
355
sound/soc/codecs/Makefile
Executable file
|
|
@ -0,0 +1,355 @@
|
|||
snd-soc-88pm860x-objs := 88pm860x-codec.o
|
||||
snd-soc-ab8500-codec-objs := ab8500-codec.o
|
||||
snd-soc-ac97-objs := ac97.o
|
||||
snd-soc-ad1836-objs := ad1836.o
|
||||
snd-soc-ad193x-objs := ad193x.o
|
||||
snd-soc-ad193x-spi-objs := ad193x-spi.o
|
||||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau1373-objs := adau1373.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau17x1-objs := adau17x1.o
|
||||
snd-soc-adau1761-objs := adau1761.o
|
||||
snd-soc-adau1761-i2c-objs := adau1761-i2c.o
|
||||
snd-soc-adau1761-spi-objs := adau1761-spi.o
|
||||
snd-soc-adau1781-objs := adau1781.o
|
||||
snd-soc-adau1781-i2c-objs := adau1781-i2c.o
|
||||
snd-soc-adau1781-spi-objs := adau1781-spi.o
|
||||
snd-soc-adau1977-objs := adau1977.o
|
||||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||
snd-soc-adav80x-objs := adav80x.o
|
||||
snd-soc-adav801-objs := adav801.o
|
||||
snd-soc-adav803-objs := adav803.o
|
||||
snd-soc-ads117x-objs := ads117x.o
|
||||
snd-soc-ak4104-objs := ak4104.o
|
||||
snd-soc-ak4535-objs := ak4535.o
|
||||
snd-soc-ak4554-objs := ak4554.o
|
||||
snd-soc-ak4641-objs := ak4641.o
|
||||
snd-soc-ak4642-objs := ak4642.o
|
||||
snd-soc-ak4671-objs := ak4671.o
|
||||
snd-soc-ak5386-objs := ak5386.o
|
||||
snd-soc-arizona-objs := arizona.o
|
||||
snd-soc-cod3026-objs := cod3026x.o
|
||||
snd-soc-cod9002-objs := cod9002x.o
|
||||
snd-soc-cq93vc-objs := cq93vc.o
|
||||
snd-soc-cs35l32-objs := cs35l32.o
|
||||
snd-soc-cs42l51-objs := cs42l51.o
|
||||
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
|
||||
snd-soc-cs42l52-objs := cs42l52.o
|
||||
snd-soc-cs42l56-objs := cs42l56.o
|
||||
snd-soc-cs42l73-objs := cs42l73.o
|
||||
snd-soc-cs4265-objs := cs4265.o
|
||||
snd-soc-cs4270-objs := cs4270.o
|
||||
snd-soc-cs4271-objs := cs4271.o
|
||||
snd-soc-cs42xx8-objs := cs42xx8.o
|
||||
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-largo-objs := largo.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-da7213-objs := da7213.o
|
||||
snd-soc-da732x-objs := da732x.o
|
||||
snd-soc-da9055-objs := da9055.o
|
||||
snd-soc-bt-sco-objs := bt-sco.o
|
||||
snd-soc-dmic-objs := dmic.o
|
||||
snd-soc-es8328-objs := es8328.o
|
||||
snd-soc-es8328-i2c-objs := es8328-i2c.o
|
||||
snd-soc-es8328-spi-objs := es8328-spi.o
|
||||
snd-soc-isabelle-objs := isabelle.o
|
||||
snd-soc-jz4740-codec-objs := jz4740.o
|
||||
snd-soc-l3-objs := l3.o
|
||||
snd-soc-lm4857-objs := lm4857.o
|
||||
snd-soc-lm49453-objs := lm49453.o
|
||||
snd-soc-max9768-objs := max9768.o
|
||||
snd-soc-max98088-objs := max98088.o
|
||||
snd-soc-max98090-objs := max98090.o
|
||||
snd-soc-max98095-objs := max98095.o
|
||||
snd-soc-max9850-objs := max9850.o
|
||||
snd-soc-mc13783-objs := mc13783.o
|
||||
snd-soc-ml26124-objs := ml26124.o
|
||||
snd-soc-hdmi-codec-objs := hdmi.o
|
||||
snd-soc-pcm1681-objs := pcm1681.o
|
||||
snd-soc-pcm1792a-codec-objs := pcm1792a.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-pcm512x-objs := pcm512x.o
|
||||
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
|
||||
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
|
||||
snd-soc-rl6231-objs := rl6231.o
|
||||
snd-soc-rt286-objs := rt286.o
|
||||
snd-soc-rt5631-objs := rt5631.o
|
||||
snd-soc-rt5640-objs := rt5640.o
|
||||
snd-soc-rt5645-objs := rt5645.o
|
||||
snd-soc-rt5651-objs := rt5651.o
|
||||
snd-soc-rt5670-objs := rt5670.o
|
||||
snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
snd-soc-alc5623-objs := alc5623.o
|
||||
snd-soc-alc5632-objs := alc5632.o
|
||||
snd-soc-sigmadsp-objs := sigmadsp.o
|
||||
snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
|
||||
snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
|
||||
snd-soc-si476x-objs := si476x.o
|
||||
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
|
||||
snd-soc-sn95031-objs := sn95031.o
|
||||
snd-soc-spdif-tx-objs := spdif_transmitter.o
|
||||
snd-soc-spdif-rx-objs := spdif_receiver.o
|
||||
snd-soc-audmixer-objs := exynos-audmixer.o
|
||||
snd-soc-ssm2518-objs := ssm2518.o
|
||||
snd-soc-ssm2602-objs := ssm2602.o
|
||||
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
|
||||
snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
|
||||
snd-soc-ssm4567-objs := ssm4567.o
|
||||
snd-soc-sta32x-objs := sta32x.o
|
||||
snd-soc-sta350-objs := sta350.o
|
||||
snd-soc-sta529-objs := sta529.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
|
||||
snd-soc-tlv320aic26-objs := tlv320aic26.o
|
||||
snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
|
||||
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
snd-soc-tlv320dac33-objs := tlv320dac33.o
|
||||
snd-soc-twl4030-objs := twl4030.o
|
||||
snd-soc-twl6040-objs := twl6040.o
|
||||
snd-soc-uda134x-objs := uda134x.o
|
||||
snd-soc-uda1380-objs := uda1380.o
|
||||
snd-soc-wl1273-objs := wl1273.o
|
||||
snd-soc-wm-adsp-objs := wm_adsp.o
|
||||
snd-soc-wm0010-objs := wm0010.o
|
||||
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
|
||||
snd-soc-wm2000-objs := wm2000.o
|
||||
snd-soc-wm2200-objs := wm2200.o
|
||||
snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
|
||||
snd-soc-wm5102-objs := wm5102.o
|
||||
snd-soc-wm5110-objs := wm5110.o
|
||||
snd-soc-wm8350-objs := wm8350.o
|
||||
snd-soc-wm8400-objs := wm8400.o
|
||||
snd-soc-wm8510-objs := wm8510.o
|
||||
snd-soc-wm8523-objs := wm8523.o
|
||||
snd-soc-wm8580-objs := wm8580.o
|
||||
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-wm8737-objs := wm8737.o
|
||||
snd-soc-wm8741-objs := wm8741.o
|
||||
snd-soc-wm8750-objs := wm8750.o
|
||||
snd-soc-wm8753-objs := wm8753.o
|
||||
snd-soc-wm8770-objs := wm8770.o
|
||||
snd-soc-wm8776-objs := wm8776.o
|
||||
snd-soc-wm8782-objs := wm8782.o
|
||||
snd-soc-wm8804-objs := wm8804.o
|
||||
snd-soc-wm8900-objs := wm8900.o
|
||||
snd-soc-wm8903-objs := wm8903.o
|
||||
snd-soc-wm8904-objs := wm8904.o
|
||||
snd-soc-wm8996-objs := wm8996.o
|
||||
snd-soc-wm8940-objs := wm8940.o
|
||||
snd-soc-wm8955-objs := wm8955.o
|
||||
snd-soc-wm8960-objs := wm8960.o
|
||||
snd-soc-wm8961-objs := wm8961.o
|
||||
snd-soc-wm8962-objs := wm8962.o
|
||||
snd-soc-wm8971-objs := wm8971.o
|
||||
snd-soc-wm8974-objs := wm8974.o
|
||||
snd-soc-wm8978-objs := wm8978.o
|
||||
snd-soc-wm8983-objs := wm8983.o
|
||||
snd-soc-wm8985-objs := wm8985.o
|
||||
snd-soc-wm8988-objs := wm8988.o
|
||||
snd-soc-wm8990-objs := wm8990.o
|
||||
snd-soc-wm8991-objs := wm8991.o
|
||||
snd-soc-wm8993-objs := wm8993.o
|
||||
snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
|
||||
snd-soc-wm8995-objs := wm8995.o
|
||||
snd-soc-wm8997-objs := wm8997.o
|
||||
snd-soc-wm9081-objs := wm9081.o
|
||||
snd-soc-wm9090-objs := wm9090.o
|
||||
snd-soc-wm9705-objs := wm9705.o
|
||||
snd-soc-wm9712-objs := wm9712.o
|
||||
snd-soc-wm9713-objs := wm9713.o
|
||||
snd-soc-wm-hubs-objs := wm_hubs.o
|
||||
snd-soc-dummy-objs := dummy_codec.o
|
||||
|
||||
# Amp
|
||||
snd-soc-max9877-objs := max9877.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.o
|
||||
snd-soc-tas2552-objs := tas2552.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
|
||||
obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
|
||||
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
|
||||
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761) += snd-soc-adau1761.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761_I2C) += snd-soc-adau1761-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761_SPI) += snd-soc-adau1761-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781) += snd-soc-adau1781.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781_I2C) += snd-soc-adau1781-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||
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_AK4535) += snd-soc-ak4535.o
|
||||
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
|
||||
obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
|
||||
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
|
||||
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
|
||||
obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.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_COD3026X) += snd-soc-cod3026.o
|
||||
obj-$(CONFIG_SND_SOC_COD9002X) += snd-soc-cod9002.o
|
||||
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
|
||||
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
|
||||
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
|
||||
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
|
||||
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_LARGO) += snd-soc-largo.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
|
||||
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
|
||||
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
|
||||
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
|
||||
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
|
||||
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
|
||||
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
|
||||
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
|
||||
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
|
||||
obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
|
||||
obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
|
||||
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
|
||||
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
|
||||
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
|
||||
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
|
||||
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
|
||||
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
|
||||
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
|
||||
obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
|
||||
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
|
||||
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
|
||||
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
|
||||
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
|
||||
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
|
||||
obj-$(CONFIG_SND_SOC_EXYNOS_AUDMIXER) += snd-soc-audmixer.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
|
||||
obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o
|
||||
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
|
||||
obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o
|
||||
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
|
||||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.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
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
|
||||
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
|
||||
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
|
||||
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
|
||||
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
|
||||
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
|
||||
obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o
|
||||
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
|
||||
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
|
||||
obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o
|
||||
obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o
|
||||
obj-$(CONFIG_SND_SOC_WM5102) += snd-soc-wm5102.o
|
||||
obj-$(CONFIG_SND_SOC_WM5110) += snd-soc-wm5110.o
|
||||
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
|
||||
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
|
||||
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
|
||||
obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o
|
||||
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
|
||||
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_WM8737) += snd-soc-wm8737.o
|
||||
obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
|
||||
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
|
||||
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
|
||||
obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o
|
||||
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
|
||||
obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o
|
||||
obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
|
||||
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
|
||||
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
|
||||
obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
|
||||
obj-$(CONFIG_SND_SOC_WM8996) += snd-soc-wm8996.o
|
||||
obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
|
||||
obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
|
||||
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
|
||||
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
|
||||
obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o
|
||||
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
|
||||
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
|
||||
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
|
||||
obj-$(CONFIG_SND_SOC_WM8983) += snd-soc-wm8983.o
|
||||
obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o
|
||||
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
|
||||
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
|
||||
obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o
|
||||
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
|
||||
obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
|
||||
obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o
|
||||
obj-$(CONFIG_SND_SOC_WM8997) += snd-soc-wm8997.o
|
||||
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
|
||||
obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o
|
||||
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
|
||||
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
|
||||
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
|
||||
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
|
||||
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
|
||||
obj-$(CONFIG_SND_SOC_DUMMY_CODEC) += snd-soc-dummy.o
|
||||
|
||||
# Amp
|
||||
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
|
||||
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
|
||||
2621
sound/soc/codecs/ab8500-codec.c
Normal file
2621
sound/soc/codecs/ab8500-codec.c
Normal file
File diff suppressed because it is too large
Load diff
592
sound/soc/codecs/ab8500-codec.h
Normal file
592
sound/soc/codecs/ab8500-codec.h
Normal file
|
|
@ -0,0 +1,592 @@
|
|||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2012
|
||||
*
|
||||
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
|
||||
* Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
|
||||
* Roger Nilsson <roger.xr.nilsson@stericsson.com>,
|
||||
* for ST-Ericsson.
|
||||
*
|
||||
* Based on the early work done by:
|
||||
* Mikko J. Lehto <mikko.lehto@symbio.com>,
|
||||
* Mikko Sarmanne <mikko.sarmanne@symbio.com>,
|
||||
* for ST-Ericsson.
|
||||
*
|
||||
* License terms:
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef AB8500_CODEC_REGISTERS_H
|
||||
#define AB8500_CODEC_REGISTERS_H
|
||||
|
||||
#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
|
||||
#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
/* AB8500 interface slot offset definitions */
|
||||
|
||||
#define AB8500_AD_DATA0_OFFSET 0
|
||||
#define AB8500_DA_DATA0_OFFSET 8
|
||||
#define AB8500_AD_DATA1_OFFSET 16
|
||||
#define AB8500_DA_DATA1_OFFSET 24
|
||||
|
||||
/* AB8500 audio bank (0x0d) register definitions */
|
||||
|
||||
#define AB8500_POWERUP 0x00
|
||||
#define AB8500_AUDSWRESET 0x01
|
||||
#define AB8500_ADPATHENA 0x02
|
||||
#define AB8500_DAPATHENA 0x03
|
||||
#define AB8500_ANACONF1 0x04
|
||||
#define AB8500_ANACONF2 0x05
|
||||
#define AB8500_DIGMICCONF 0x06
|
||||
#define AB8500_ANACONF3 0x07
|
||||
#define AB8500_ANACONF4 0x08
|
||||
#define AB8500_DAPATHCONF 0x09
|
||||
#define AB8500_MUTECONF 0x0A
|
||||
#define AB8500_SHORTCIRCONF 0x0B
|
||||
#define AB8500_ANACONF5 0x0C
|
||||
#define AB8500_ENVCPCONF 0x0D
|
||||
#define AB8500_SIGENVCONF 0x0E
|
||||
#define AB8500_PWMGENCONF1 0x0F
|
||||
#define AB8500_PWMGENCONF2 0x10
|
||||
#define AB8500_PWMGENCONF3 0x11
|
||||
#define AB8500_PWMGENCONF4 0x12
|
||||
#define AB8500_PWMGENCONF5 0x13
|
||||
#define AB8500_ANAGAIN1 0x14
|
||||
#define AB8500_ANAGAIN2 0x15
|
||||
#define AB8500_ANAGAIN3 0x16
|
||||
#define AB8500_ANAGAIN4 0x17
|
||||
#define AB8500_DIGLINHSLGAIN 0x18
|
||||
#define AB8500_DIGLINHSRGAIN 0x19
|
||||
#define AB8500_ADFILTCONF 0x1A
|
||||
#define AB8500_DIGIFCONF1 0x1B
|
||||
#define AB8500_DIGIFCONF2 0x1C
|
||||
#define AB8500_DIGIFCONF3 0x1D
|
||||
#define AB8500_DIGIFCONF4 0x1E
|
||||
#define AB8500_ADSLOTSEL1 0x1F
|
||||
#define AB8500_ADSLOTSEL2 0x20
|
||||
#define AB8500_ADSLOTSEL3 0x21
|
||||
#define AB8500_ADSLOTSEL4 0x22
|
||||
#define AB8500_ADSLOTSEL5 0x23
|
||||
#define AB8500_ADSLOTSEL6 0x24
|
||||
#define AB8500_ADSLOTSEL7 0x25
|
||||
#define AB8500_ADSLOTSEL8 0x26
|
||||
#define AB8500_ADSLOTSEL9 0x27
|
||||
#define AB8500_ADSLOTSEL10 0x28
|
||||
#define AB8500_ADSLOTSEL11 0x29
|
||||
#define AB8500_ADSLOTSEL12 0x2A
|
||||
#define AB8500_ADSLOTSEL13 0x2B
|
||||
#define AB8500_ADSLOTSEL14 0x2C
|
||||
#define AB8500_ADSLOTSEL15 0x2D
|
||||
#define AB8500_ADSLOTSEL16 0x2E
|
||||
#define AB8500_ADSLOTSEL(slot) (AB8500_ADSLOTSEL1 + (slot >> 1))
|
||||
#define AB8500_ADSLOTHIZCTRL1 0x2F
|
||||
#define AB8500_ADSLOTHIZCTRL2 0x30
|
||||
#define AB8500_ADSLOTHIZCTRL3 0x31
|
||||
#define AB8500_ADSLOTHIZCTRL4 0x32
|
||||
#define AB8500_DASLOTCONF1 0x33
|
||||
#define AB8500_DASLOTCONF2 0x34
|
||||
#define AB8500_DASLOTCONF3 0x35
|
||||
#define AB8500_DASLOTCONF4 0x36
|
||||
#define AB8500_DASLOTCONF5 0x37
|
||||
#define AB8500_DASLOTCONF6 0x38
|
||||
#define AB8500_DASLOTCONF7 0x39
|
||||
#define AB8500_DASLOTCONF8 0x3A
|
||||
#define AB8500_CLASSDCONF1 0x3B
|
||||
#define AB8500_CLASSDCONF2 0x3C
|
||||
#define AB8500_CLASSDCONF3 0x3D
|
||||
#define AB8500_DMICFILTCONF 0x3E
|
||||
#define AB8500_DIGMULTCONF1 0x3F
|
||||
#define AB8500_DIGMULTCONF2 0x40
|
||||
#define AB8500_ADDIGGAIN1 0x41
|
||||
#define AB8500_ADDIGGAIN2 0x42
|
||||
#define AB8500_ADDIGGAIN3 0x43
|
||||
#define AB8500_ADDIGGAIN4 0x44
|
||||
#define AB8500_ADDIGGAIN5 0x45
|
||||
#define AB8500_ADDIGGAIN6 0x46
|
||||
#define AB8500_DADIGGAIN1 0x47
|
||||
#define AB8500_DADIGGAIN2 0x48
|
||||
#define AB8500_DADIGGAIN3 0x49
|
||||
#define AB8500_DADIGGAIN4 0x4A
|
||||
#define AB8500_DADIGGAIN5 0x4B
|
||||
#define AB8500_DADIGGAIN6 0x4C
|
||||
#define AB8500_ADDIGLOOPGAIN1 0x4D
|
||||
#define AB8500_ADDIGLOOPGAIN2 0x4E
|
||||
#define AB8500_HSLEARDIGGAIN 0x4F
|
||||
#define AB8500_HSRDIGGAIN 0x50
|
||||
#define AB8500_SIDFIRGAIN1 0x51
|
||||
#define AB8500_SIDFIRGAIN2 0x52
|
||||
#define AB8500_ANCCONF1 0x53
|
||||
#define AB8500_ANCCONF2 0x54
|
||||
#define AB8500_ANCCONF3 0x55
|
||||
#define AB8500_ANCCONF4 0x56
|
||||
#define AB8500_ANCCONF5 0x57
|
||||
#define AB8500_ANCCONF6 0x58
|
||||
#define AB8500_ANCCONF7 0x59
|
||||
#define AB8500_ANCCONF8 0x5A
|
||||
#define AB8500_ANCCONF9 0x5B
|
||||
#define AB8500_ANCCONF10 0x5C
|
||||
#define AB8500_ANCCONF11 0x5D
|
||||
#define AB8500_ANCCONF12 0x5E
|
||||
#define AB8500_ANCCONF13 0x5F
|
||||
#define AB8500_ANCCONF14 0x60
|
||||
#define AB8500_SIDFIRADR 0x61
|
||||
#define AB8500_SIDFIRCOEF1 0x62
|
||||
#define AB8500_SIDFIRCOEF2 0x63
|
||||
#define AB8500_SIDFIRCONF 0x64
|
||||
#define AB8500_AUDINTMASK1 0x65
|
||||
#define AB8500_AUDINTSOURCE1 0x66
|
||||
#define AB8500_AUDINTMASK2 0x67
|
||||
#define AB8500_AUDINTSOURCE2 0x68
|
||||
#define AB8500_FIFOCONF1 0x69
|
||||
#define AB8500_FIFOCONF2 0x6A
|
||||
#define AB8500_FIFOCONF3 0x6B
|
||||
#define AB8500_FIFOCONF4 0x6C
|
||||
#define AB8500_FIFOCONF5 0x6D
|
||||
#define AB8500_FIFOCONF6 0x6E
|
||||
#define AB8500_AUDREV 0x6F
|
||||
|
||||
#define AB8500_FIRST_REG AB8500_POWERUP
|
||||
#define AB8500_LAST_REG AB8500_AUDREV
|
||||
#define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1)
|
||||
|
||||
#define AB8500_MASK_ALL 0xFF
|
||||
#define AB8500_MASK_SLOT(slot) ((slot & 1) ? 0xF0 : 0x0F)
|
||||
#define AB8500_MASK_NONE 0x00
|
||||
|
||||
/* AB8500_POWERUP */
|
||||
#define AB8500_POWERUP_POWERUP 7
|
||||
#define AB8500_POWERUP_ENANA 3
|
||||
|
||||
/* AB8500_AUDSWRESET */
|
||||
#define AB8500_AUDSWRESET_SWRESET 7
|
||||
|
||||
/* AB8500_ADPATHENA */
|
||||
#define AB8500_ADPATHENA_ENAD12 7
|
||||
#define AB8500_ADPATHENA_ENAD34 5
|
||||
#define AB8500_ADPATHENA_ENAD5768 3
|
||||
|
||||
/* AB8500_DAPATHENA */
|
||||
#define AB8500_DAPATHENA_ENDA1 7
|
||||
#define AB8500_DAPATHENA_ENDA2 6
|
||||
#define AB8500_DAPATHENA_ENDA3 5
|
||||
#define AB8500_DAPATHENA_ENDA4 4
|
||||
#define AB8500_DAPATHENA_ENDA5 3
|
||||
#define AB8500_DAPATHENA_ENDA6 2
|
||||
|
||||
/* AB8500_ANACONF1 */
|
||||
#define AB8500_ANACONF1_HSLOWPOW 7
|
||||
#define AB8500_ANACONF1_DACLOWPOW1 6
|
||||
#define AB8500_ANACONF1_DACLOWPOW0 5
|
||||
#define AB8500_ANACONF1_EARDACLOWPOW 4
|
||||
#define AB8500_ANACONF1_EARSELCM 2
|
||||
#define AB8500_ANACONF1_HSHPEN 1
|
||||
#define AB8500_ANACONF1_EARDRVLOWPOW 0
|
||||
|
||||
/* AB8500_ANACONF2 */
|
||||
#define AB8500_ANACONF2_ENMIC1 7
|
||||
#define AB8500_ANACONF2_ENMIC2 6
|
||||
#define AB8500_ANACONF2_ENLINL 5
|
||||
#define AB8500_ANACONF2_ENLINR 4
|
||||
#define AB8500_ANACONF2_MUTMIC1 3
|
||||
#define AB8500_ANACONF2_MUTMIC2 2
|
||||
#define AB8500_ANACONF2_MUTLINL 1
|
||||
#define AB8500_ANACONF2_MUTLINR 0
|
||||
|
||||
/* AB8500_DIGMICCONF */
|
||||
#define AB8500_DIGMICCONF_ENDMIC1 7
|
||||
#define AB8500_DIGMICCONF_ENDMIC2 6
|
||||
#define AB8500_DIGMICCONF_ENDMIC3 5
|
||||
#define AB8500_DIGMICCONF_ENDMIC4 4
|
||||
#define AB8500_DIGMICCONF_ENDMIC5 3
|
||||
#define AB8500_DIGMICCONF_ENDMIC6 2
|
||||
#define AB8500_DIGMICCONF_HSFADSPEED 0
|
||||
|
||||
/* AB8500_ANACONF3 */
|
||||
#define AB8500_ANACONF3_MIC1SEL 7
|
||||
#define AB8500_ANACONF3_LINRSEL 6
|
||||
#define AB8500_ANACONF3_ENDRVHSL 5
|
||||
#define AB8500_ANACONF3_ENDRVHSR 4
|
||||
#define AB8500_ANACONF3_ENADCMIC 2
|
||||
#define AB8500_ANACONF3_ENADCLINL 1
|
||||
#define AB8500_ANACONF3_ENADCLINR 0
|
||||
|
||||
/* AB8500_ANACONF4 */
|
||||
#define AB8500_ANACONF4_DISPDVSS 7
|
||||
#define AB8500_ANACONF4_ENEAR 6
|
||||
#define AB8500_ANACONF4_ENHSL 5
|
||||
#define AB8500_ANACONF4_ENHSR 4
|
||||
#define AB8500_ANACONF4_ENHFL 3
|
||||
#define AB8500_ANACONF4_ENHFR 2
|
||||
#define AB8500_ANACONF4_ENVIB1 1
|
||||
#define AB8500_ANACONF4_ENVIB2 0
|
||||
|
||||
/* AB8500_DAPATHCONF */
|
||||
#define AB8500_DAPATHCONF_ENDACEAR 6
|
||||
#define AB8500_DAPATHCONF_ENDACHSL 5
|
||||
#define AB8500_DAPATHCONF_ENDACHSR 4
|
||||
#define AB8500_DAPATHCONF_ENDACHFL 3
|
||||
#define AB8500_DAPATHCONF_ENDACHFR 2
|
||||
#define AB8500_DAPATHCONF_ENDACVIB1 1
|
||||
#define AB8500_DAPATHCONF_ENDACVIB2 0
|
||||
|
||||
/* AB8500_MUTECONF */
|
||||
#define AB8500_MUTECONF_MUTEAR 6
|
||||
#define AB8500_MUTECONF_MUTHSL 5
|
||||
#define AB8500_MUTECONF_MUTHSR 4
|
||||
#define AB8500_MUTECONF_MUTDACEAR 2
|
||||
#define AB8500_MUTECONF_MUTDACHSL 1
|
||||
#define AB8500_MUTECONF_MUTDACHSR 0
|
||||
|
||||
/* AB8500_SHORTCIRCONF */
|
||||
#define AB8500_SHORTCIRCONF_ENSHORTPWD 7
|
||||
#define AB8500_SHORTCIRCONF_EARSHORTDIS 6
|
||||
#define AB8500_SHORTCIRCONF_HSSHORTDIS 5
|
||||
#define AB8500_SHORTCIRCONF_HSPULLDEN 4
|
||||
#define AB8500_SHORTCIRCONF_HSOSCEN 2
|
||||
#define AB8500_SHORTCIRCONF_HSFADDIS 1
|
||||
#define AB8500_SHORTCIRCONF_HSZCDDIS 0
|
||||
/* Zero cross should be disabled */
|
||||
|
||||
/* AB8500_ANACONF5 */
|
||||
#define AB8500_ANACONF5_ENCPHS 7
|
||||
#define AB8500_ANACONF5_HSLDACTOLOL 5
|
||||
#define AB8500_ANACONF5_HSRDACTOLOR 4
|
||||
#define AB8500_ANACONF5_ENLOL 3
|
||||
#define AB8500_ANACONF5_ENLOR 2
|
||||
#define AB8500_ANACONF5_HSAUTOEN 0
|
||||
|
||||
/* AB8500_ENVCPCONF */
|
||||
#define AB8500_ENVCPCONF_ENVDETHTHRE 4
|
||||
#define AB8500_ENVCPCONF_ENVDETLTHRE 0
|
||||
#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX 0x0F
|
||||
#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX 0x0F
|
||||
|
||||
/* AB8500_SIGENVCONF */
|
||||
#define AB8500_SIGENVCONF_CPLVEN 5
|
||||
#define AB8500_SIGENVCONF_ENVDETCPEN 4
|
||||
#define AB8500_SIGENVCONF_ENVDETTIME 0
|
||||
#define AB8500_SIGENVCONF_ENVDETTIME_MAX 0x0F
|
||||
|
||||
/* AB8500_PWMGENCONF1 */
|
||||
#define AB8500_PWMGENCONF1_PWMTOVIB1 7
|
||||
#define AB8500_PWMGENCONF1_PWMTOVIB2 6
|
||||
#define AB8500_PWMGENCONF1_PWM1CTRL 5
|
||||
#define AB8500_PWMGENCONF1_PWM2CTRL 4
|
||||
#define AB8500_PWMGENCONF1_PWM1NCTRL 3
|
||||
#define AB8500_PWMGENCONF1_PWM1PCTRL 2
|
||||
#define AB8500_PWMGENCONF1_PWM2NCTRL 1
|
||||
#define AB8500_PWMGENCONF1_PWM2PCTRL 0
|
||||
|
||||
/* AB8500_PWMGENCONF2 */
|
||||
/* AB8500_PWMGENCONF3 */
|
||||
/* AB8500_PWMGENCONF4 */
|
||||
/* AB8500_PWMGENCONF5 */
|
||||
#define AB8500_PWMGENCONFX_PWMVIBXPOL 7
|
||||
#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC 0
|
||||
#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX 0x64
|
||||
|
||||
/* AB8500_ANAGAIN1 */
|
||||
/* AB8500_ANAGAIN2 */
|
||||
#define AB8500_ANAGAINX_ENSEMICX 7
|
||||
#define AB8500_ANAGAINX_LOWPOWMICX 6
|
||||
#define AB8500_ANAGAINX_MICXGAIN 0
|
||||
#define AB8500_ANAGAINX_MICXGAIN_MAX 0x1F
|
||||
|
||||
/* AB8500_ANAGAIN3 */
|
||||
#define AB8500_ANAGAIN3_HSLGAIN 4
|
||||
#define AB8500_ANAGAIN3_HSRGAIN 0
|
||||
#define AB8500_ANAGAIN3_HSXGAIN_MAX 0x0F
|
||||
|
||||
/* AB8500_ANAGAIN4 */
|
||||
#define AB8500_ANAGAIN4_LINLGAIN 4
|
||||
#define AB8500_ANAGAIN4_LINRGAIN 0
|
||||
#define AB8500_ANAGAIN4_LINXGAIN_MAX 0x0F
|
||||
|
||||
/* AB8500_DIGLINHSLGAIN */
|
||||
/* AB8500_DIGLINHSRGAIN */
|
||||
#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN 0
|
||||
#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX 0x13
|
||||
|
||||
/* AB8500_ADFILTCONF */
|
||||
#define AB8500_ADFILTCONF_AD1NH 7
|
||||
#define AB8500_ADFILTCONF_AD2NH 6
|
||||
#define AB8500_ADFILTCONF_AD3NH 5
|
||||
#define AB8500_ADFILTCONF_AD4NH 4
|
||||
#define AB8500_ADFILTCONF_AD1VOICE 3
|
||||
#define AB8500_ADFILTCONF_AD2VOICE 2
|
||||
#define AB8500_ADFILTCONF_AD3VOICE 1
|
||||
#define AB8500_ADFILTCONF_AD4VOICE 0
|
||||
|
||||
/* AB8500_DIGIFCONF1 */
|
||||
#define AB8500_DIGIFCONF1_ENMASTGEN 7
|
||||
#define AB8500_DIGIFCONF1_IF1BITCLKOS1 6
|
||||
#define AB8500_DIGIFCONF1_IF1BITCLKOS0 5
|
||||
#define AB8500_DIGIFCONF1_ENFSBITCLK1 4
|
||||
#define AB8500_DIGIFCONF1_IF0BITCLKOS1 2
|
||||
#define AB8500_DIGIFCONF1_IF0BITCLKOS0 1
|
||||
#define AB8500_DIGIFCONF1_ENFSBITCLK0 0
|
||||
|
||||
/* AB8500_DIGIFCONF2 */
|
||||
#define AB8500_DIGIFCONF2_FSYNC0P 6
|
||||
#define AB8500_DIGIFCONF2_BITCLK0P 5
|
||||
#define AB8500_DIGIFCONF2_IF0DEL 4
|
||||
#define AB8500_DIGIFCONF2_IF0FORMAT1 3
|
||||
#define AB8500_DIGIFCONF2_IF0FORMAT0 2
|
||||
#define AB8500_DIGIFCONF2_IF0WL1 1
|
||||
#define AB8500_DIGIFCONF2_IF0WL0 0
|
||||
|
||||
/* AB8500_DIGIFCONF3 */
|
||||
#define AB8500_DIGIFCONF3_IF0DATOIF1AD 7
|
||||
#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK 6
|
||||
#define AB8500_DIGIFCONF3_IF1MASTER 5
|
||||
#define AB8500_DIGIFCONF3_IF1DATOIF0AD 3
|
||||
#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK 2
|
||||
#define AB8500_DIGIFCONF3_IF0MASTER 1
|
||||
#define AB8500_DIGIFCONF3_IF0BFIFOEN 0
|
||||
|
||||
/* AB8500_DIGIFCONF4 */
|
||||
#define AB8500_DIGIFCONF4_FSYNC1P 6
|
||||
#define AB8500_DIGIFCONF4_BITCLK1P 5
|
||||
#define AB8500_DIGIFCONF4_IF1DEL 4
|
||||
#define AB8500_DIGIFCONF4_IF1FORMAT1 3
|
||||
#define AB8500_DIGIFCONF4_IF1FORMAT0 2
|
||||
#define AB8500_DIGIFCONF4_IF1WL1 1
|
||||
#define AB8500_DIGIFCONF4_IF1WL0 0
|
||||
|
||||
/* AB8500_ADSLOTSELX */
|
||||
#define AB8500_AD_OUT1 0x0
|
||||
#define AB8500_AD_OUT2 0x1
|
||||
#define AB8500_AD_OUT3 0x2
|
||||
#define AB8500_AD_OUT4 0x3
|
||||
#define AB8500_AD_OUT5 0x4
|
||||
#define AB8500_AD_OUT6 0x5
|
||||
#define AB8500_AD_OUT7 0x6
|
||||
#define AB8500_AD_OUT8 0x7
|
||||
#define AB8500_ZEROES 0x8
|
||||
#define AB8500_TRISTATE 0xF
|
||||
#define AB8500_ADSLOTSELX_EVEN_SHIFT 0
|
||||
#define AB8500_ADSLOTSELX_ODD_SHIFT 4
|
||||
#define AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(out, slot) \
|
||||
((out) << (((slot) & 1) ? \
|
||||
AB8500_ADSLOTSELX_ODD_SHIFT : AB8500_ADSLOTSELX_EVEN_SHIFT))
|
||||
|
||||
/* AB8500_ADSLOTHIZCTRL1 */
|
||||
/* AB8500_ADSLOTHIZCTRL2 */
|
||||
/* AB8500_ADSLOTHIZCTRL3 */
|
||||
/* AB8500_ADSLOTHIZCTRL4 */
|
||||
/* AB8500_DASLOTCONF1 */
|
||||
#define AB8500_DASLOTCONF1_DA12VOICE 7
|
||||
#define AB8500_DASLOTCONF1_SWAPDA12_34 6
|
||||
#define AB8500_DASLOTCONF1_DAI7TOADO1 5
|
||||
|
||||
/* AB8500_DASLOTCONF2 */
|
||||
#define AB8500_DASLOTCONF2_DAI8TOADO2 5
|
||||
|
||||
/* AB8500_DASLOTCONF3 */
|
||||
#define AB8500_DASLOTCONF3_DA34VOICE 7
|
||||
#define AB8500_DASLOTCONF3_DAI7TOADO3 5
|
||||
|
||||
/* AB8500_DASLOTCONF4 */
|
||||
#define AB8500_DASLOTCONF4_DAI8TOADO4 5
|
||||
|
||||
/* AB8500_DASLOTCONF5 */
|
||||
#define AB8500_DASLOTCONF5_DA56VOICE 7
|
||||
#define AB8500_DASLOTCONF5_DAI7TOADO5 5
|
||||
|
||||
/* AB8500_DASLOTCONF6 */
|
||||
#define AB8500_DASLOTCONF6_DAI8TOADO6 5
|
||||
|
||||
/* AB8500_DASLOTCONF7 */
|
||||
#define AB8500_DASLOTCONF7_DAI8TOADO7 5
|
||||
|
||||
/* AB8500_DASLOTCONF8 */
|
||||
#define AB8500_DASLOTCONF8_DAI7TOADO8 5
|
||||
|
||||
#define AB8500_DASLOTCONFX_SLTODAX_SHIFT 0
|
||||
#define AB8500_DASLOTCONFX_SLTODAX_MASK 0x1F
|
||||
|
||||
/* AB8500_CLASSDCONF1 */
|
||||
#define AB8500_CLASSDCONF1_PARLHF 7
|
||||
#define AB8500_CLASSDCONF1_PARLVIB 6
|
||||
#define AB8500_CLASSDCONF1_VIB1SWAPEN 3
|
||||
#define AB8500_CLASSDCONF1_VIB2SWAPEN 2
|
||||
#define AB8500_CLASSDCONF1_HFLSWAPEN 1
|
||||
#define AB8500_CLASSDCONF1_HFRSWAPEN 0
|
||||
|
||||
/* AB8500_CLASSDCONF2 */
|
||||
#define AB8500_CLASSDCONF2_FIRBYP3 7
|
||||
#define AB8500_CLASSDCONF2_FIRBYP2 6
|
||||
#define AB8500_CLASSDCONF2_FIRBYP1 5
|
||||
#define AB8500_CLASSDCONF2_FIRBYP0 4
|
||||
#define AB8500_CLASSDCONF2_HIGHVOLEN3 3
|
||||
#define AB8500_CLASSDCONF2_HIGHVOLEN2 2
|
||||
#define AB8500_CLASSDCONF2_HIGHVOLEN1 1
|
||||
#define AB8500_CLASSDCONF2_HIGHVOLEN0 0
|
||||
|
||||
/* AB8500_CLASSDCONF3 */
|
||||
#define AB8500_CLASSDCONF3_DITHHPGAIN 4
|
||||
#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX 0x0A
|
||||
#define AB8500_CLASSDCONF3_DITHWGAIN 0
|
||||
#define AB8500_CLASSDCONF3_DITHWGAIN_MAX 0x0A
|
||||
|
||||
/* AB8500_DMICFILTCONF */
|
||||
#define AB8500_DMICFILTCONF_ANCINSEL 7
|
||||
#define AB8500_DMICFILTCONF_DA3TOEAR 6
|
||||
#define AB8500_DMICFILTCONF_DMIC1SINC3 5
|
||||
#define AB8500_DMICFILTCONF_DMIC2SINC3 4
|
||||
#define AB8500_DMICFILTCONF_DMIC3SINC3 3
|
||||
#define AB8500_DMICFILTCONF_DMIC4SINC3 2
|
||||
#define AB8500_DMICFILTCONF_DMIC5SINC3 1
|
||||
#define AB8500_DMICFILTCONF_DMIC6SINC3 0
|
||||
|
||||
/* AB8500_DIGMULTCONF1 */
|
||||
#define AB8500_DIGMULTCONF1_DATOHSLEN 7
|
||||
#define AB8500_DIGMULTCONF1_DATOHSREN 6
|
||||
#define AB8500_DIGMULTCONF1_AD1SEL 5
|
||||
#define AB8500_DIGMULTCONF1_AD2SEL 4
|
||||
#define AB8500_DIGMULTCONF1_AD3SEL 3
|
||||
#define AB8500_DIGMULTCONF1_AD5SEL 2
|
||||
#define AB8500_DIGMULTCONF1_AD6SEL 1
|
||||
#define AB8500_DIGMULTCONF1_ANCSEL 0
|
||||
|
||||
/* AB8500_DIGMULTCONF2 */
|
||||
#define AB8500_DIGMULTCONF2_DATOHFREN 7
|
||||
#define AB8500_DIGMULTCONF2_DATOHFLEN 6
|
||||
#define AB8500_DIGMULTCONF2_HFRSEL 5
|
||||
#define AB8500_DIGMULTCONF2_HFLSEL 4
|
||||
#define AB8500_DIGMULTCONF2_FIRSID1SEL 2
|
||||
#define AB8500_DIGMULTCONF2_FIRSID2SEL 0
|
||||
|
||||
/* AB8500_ADDIGGAIN1 */
|
||||
/* AB8500_ADDIGGAIN2 */
|
||||
/* AB8500_ADDIGGAIN3 */
|
||||
/* AB8500_ADDIGGAIN4 */
|
||||
/* AB8500_ADDIGGAIN5 */
|
||||
/* AB8500_ADDIGGAIN6 */
|
||||
#define AB8500_ADDIGGAINX_FADEDISADX 6
|
||||
#define AB8500_ADDIGGAINX_ADXGAIN_MAX 0x3F
|
||||
|
||||
/* AB8500_DADIGGAIN1 */
|
||||
/* AB8500_DADIGGAIN2 */
|
||||
/* AB8500_DADIGGAIN3 */
|
||||
/* AB8500_DADIGGAIN4 */
|
||||
/* AB8500_DADIGGAIN5 */
|
||||
/* AB8500_DADIGGAIN6 */
|
||||
#define AB8500_DADIGGAINX_FADEDISDAX 6
|
||||
#define AB8500_DADIGGAINX_DAXGAIN_MAX 0x3F
|
||||
|
||||
/* AB8500_ADDIGLOOPGAIN1 */
|
||||
/* AB8500_ADDIGLOOPGAIN2 */
|
||||
#define AB8500_ADDIGLOOPGAINX_FADEDISADXL 6
|
||||
#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX 0x3F
|
||||
|
||||
/* AB8500_HSLEARDIGGAIN */
|
||||
#define AB8500_HSLEARDIGGAIN_HSSINC1 7
|
||||
#define AB8500_HSLEARDIGGAIN_FADEDISHSL 4
|
||||
#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX 0x09
|
||||
|
||||
/* AB8500_HSRDIGGAIN */
|
||||
#define AB8500_HSRDIGGAIN_FADESPEED 6
|
||||
#define AB8500_HSRDIGGAIN_FADEDISHSR 4
|
||||
#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX 0x09
|
||||
|
||||
/* AB8500_SIDFIRGAIN1 */
|
||||
/* AB8500_SIDFIRGAIN2 */
|
||||
#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX 0x1F
|
||||
|
||||
/* AB8500_ANCCONF1 */
|
||||
#define AB8500_ANCCONF1_ANCIIRUPDATE 3
|
||||
#define AB8500_ANCCONF1_ENANC 2
|
||||
#define AB8500_ANCCONF1_ANCIIRINIT 1
|
||||
#define AB8500_ANCCONF1_ANCFIRUPDATE 0
|
||||
|
||||
/* AB8500_ANCCONF2 */
|
||||
#define AB8500_ANCCONF2_SHIFT 5
|
||||
#define AB8500_ANCCONF2_MIN -0x10
|
||||
#define AB8500_ANCCONF2_MAX 0xF
|
||||
|
||||
/* AB8500_ANCCONF3 */
|
||||
#define AB8500_ANCCONF3_SHIFT 5
|
||||
#define AB8500_ANCCONF3_MIN -0x10
|
||||
#define AB8500_ANCCONF3_MAX 0xF
|
||||
|
||||
/* AB8500_ANCCONF4 */
|
||||
#define AB8500_ANCCONF4_SHIFT 5
|
||||
#define AB8500_ANCCONF4_MIN -0x10
|
||||
#define AB8500_ANCCONF4_MAX 0xF
|
||||
|
||||
/* AB8500_ANC_FIR_COEFFS */
|
||||
#define AB8500_ANC_FIR_COEFF_MIN -0x8000
|
||||
#define AB8500_ANC_FIR_COEFF_MAX 0x7FFF
|
||||
#define AB8500_ANC_FIR_COEFFS 15
|
||||
|
||||
/* AB8500_ANC_IIR_COEFFS */
|
||||
#define AB8500_ANC_IIR_COEFF_MIN -0x800000
|
||||
#define AB8500_ANC_IIR_COEFF_MAX 0x7FFFFF
|
||||
#define AB8500_ANC_IIR_COEFFS 24
|
||||
/* AB8500_ANC_WARP_DELAY */
|
||||
#define AB8500_ANC_WARP_DELAY_SHIFT 16
|
||||
#define AB8500_ANC_WARP_DELAY_MIN 0x0000
|
||||
#define AB8500_ANC_WARP_DELAY_MAX 0xFFFF
|
||||
|
||||
/* AB8500_ANCCONF11 */
|
||||
/* AB8500_ANCCONF12 */
|
||||
/* AB8500_ANCCONF13 */
|
||||
/* AB8500_ANCCONF14 */
|
||||
|
||||
/* AB8500_SIDFIRADR */
|
||||
#define AB8500_SIDFIRADR_FIRSIDSET 7
|
||||
#define AB8500_SIDFIRADR_ADDRESS_SHIFT 0
|
||||
#define AB8500_SIDFIRADR_ADDRESS_MAX 0x7F
|
||||
|
||||
/* AB8500_SIDFIRCOEF1 */
|
||||
/* AB8500_SIDFIRCOEF2 */
|
||||
#define AB8500_SID_FIR_COEFF_MIN 0
|
||||
#define AB8500_SID_FIR_COEFF_MAX 0xFFFF
|
||||
#define AB8500_SID_FIR_COEFFS 128
|
||||
|
||||
/* AB8500_SIDFIRCONF */
|
||||
#define AB8500_SIDFIRCONF_ENFIRSIDS 2
|
||||
#define AB8500_SIDFIRCONF_FIRSIDSTOIF1 1
|
||||
#define AB8500_SIDFIRCONF_FIRSIDBUSY 0
|
||||
|
||||
/* AB8500_AUDINTMASK1 */
|
||||
/* AB8500_AUDINTSOURCE1 */
|
||||
/* AB8500_AUDINTMASK2 */
|
||||
/* AB8500_AUDINTSOURCE2 */
|
||||
|
||||
/* AB8500_FIFOCONF1 */
|
||||
#define AB8500_FIFOCONF1_BFIFOMASK 0x80
|
||||
#define AB8500_FIFOCONF1_BFIFO19M2 0x40
|
||||
#define AB8500_FIFOCONF1_BFIFOINT_SHIFT 0
|
||||
#define AB8500_FIFOCONF1_BFIFOINT_MAX 0x3F
|
||||
|
||||
/* AB8500_FIFOCONF2 */
|
||||
#define AB8500_FIFOCONF2_BFIFOTX_SHIFT 0
|
||||
#define AB8500_FIFOCONF2_BFIFOTX_MAX 0xFF
|
||||
|
||||
/* AB8500_FIFOCONF3 */
|
||||
#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT 5
|
||||
#define AB8500_FIFOCONF3_BFIFOEXSL_MAX 0x5
|
||||
#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT 2
|
||||
#define AB8500_FIFOCONF3_PREBITCLK0_MAX 0x7
|
||||
#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT 1
|
||||
#define AB8500_FIFOCONF3_BFIFORUN_SHIFT 0
|
||||
|
||||
/* AB8500_FIFOCONF4 */
|
||||
#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT 0
|
||||
#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX 0xFF
|
||||
|
||||
/* AB8500_FIFOCONF5 */
|
||||
#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT 0
|
||||
#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX 0xFF
|
||||
|
||||
/* AB8500_FIFOCONF6 */
|
||||
#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT 0
|
||||
#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX 0xFF
|
||||
|
||||
/* AB8500_AUDREV */
|
||||
|
||||
#endif
|
||||
149
sound/soc/codecs/ac97.c
Normal file
149
sound/soc/codecs/ac97.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* ac97.c -- ALSA Soc AC97 codec support
|
||||
*
|
||||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Generic AC97 support.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget ac97_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("RX"),
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ac97_routes[] = {
|
||||
{ "AC97 Capture", NULL, "RX" },
|
||||
{ "TX", NULL, "AC97 Playback" },
|
||||
};
|
||||
|
||||
static int ac97_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
|
||||
return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
|
||||
}
|
||||
|
||||
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
|
||||
SNDRV_PCM_RATE_48000)
|
||||
|
||||
static const struct snd_soc_dai_ops ac97_dai_ops = {
|
||||
.prepare = ac97_prepare,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ac97_dai = {
|
||||
.name = "ac97-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = STD_AC97_RATES,
|
||||
.formats = SND_SOC_STD_AC97_FMTS,},
|
||||
.capture = {
|
||||
.stream_name = "AC97 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = STD_AC97_RATES,
|
||||
.formats = SND_SOC_STD_AC97_FMTS,},
|
||||
.ops = &ac97_dai_ops,
|
||||
};
|
||||
|
||||
static int ac97_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_ac97_bus *ac97_bus;
|
||||
struct snd_ac97_template ac97_template;
|
||||
int ret;
|
||||
|
||||
/* add codec as bus device for standard ac97 */
|
||||
ret = snd_ac97_bus(codec->component.card->snd_card, 0, soc_ac97_ops,
|
||||
NULL, &ac97_bus);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
|
||||
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ac97_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_ac97_suspend(codec->ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac97_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_ac97_resume(codec->ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ac97_soc_suspend NULL
|
||||
#define ac97_soc_resume NULL
|
||||
#endif
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
|
||||
.probe = ac97_soc_probe,
|
||||
.suspend = ac97_soc_suspend,
|
||||
.resume = ac97_soc_resume,
|
||||
|
||||
.dapm_widgets = ac97_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
|
||||
.dapm_routes = ac97_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ac97_routes),
|
||||
};
|
||||
|
||||
static int ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ac97, &ac97_dai, 1);
|
||||
}
|
||||
|
||||
static int ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ac97_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ac97-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ac97_probe,
|
||||
.remove = ac97_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ac97_codec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Soc Generic AC97 driver");
|
||||
MODULE_AUTHOR("Liam Girdwood");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:ac97-codec");
|
||||
418
sound/soc/codecs/ad1836.c
Normal file
418
sound/soc/codecs/ad1836.c
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* Audio Codec driver supporting:
|
||||
* AD1835A, AD1836, AD1837A, AD1838A, AD1839A
|
||||
*
|
||||
* Copyright 2009-2011 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "ad1836.h"
|
||||
|
||||
enum ad1836_type {
|
||||
AD1835,
|
||||
AD1836,
|
||||
AD1838,
|
||||
};
|
||||
|
||||
/* codec private data */
|
||||
struct ad1836_priv {
|
||||
enum ad1836_type type;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* AD1836 volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum,
|
||||
AD1836_DAC_CTRL1, 8, ad1836_deemp);
|
||||
|
||||
#define AD1836_DAC_VOLUME(x) \
|
||||
SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
|
||||
AD1836_DAC_R_VOL(x), 0, 0x3FF, 0)
|
||||
|
||||
#define AD1836_DAC_SWITCH(x) \
|
||||
SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \
|
||||
AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
|
||||
|
||||
#define AD1836_ADC_SWITCH(x) \
|
||||
SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \
|
||||
AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
|
||||
|
||||
static const struct snd_kcontrol_new ad183x_dac_controls[] = {
|
||||
AD1836_DAC_VOLUME(1),
|
||||
AD1836_DAC_SWITCH(1),
|
||||
AD1836_DAC_VOLUME(2),
|
||||
AD1836_DAC_SWITCH(2),
|
||||
AD1836_DAC_VOLUME(3),
|
||||
AD1836_DAC_SWITCH(3),
|
||||
AD1836_DAC_VOLUME(4),
|
||||
AD1836_DAC_SWITCH(4),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC4OUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad183x_dac_routes[] = {
|
||||
{ "DAC1OUT", NULL, "DAC" },
|
||||
{ "DAC2OUT", NULL, "DAC" },
|
||||
{ "DAC3OUT", NULL, "DAC" },
|
||||
{ "DAC4OUT", NULL, "DAC" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ad183x_adc_controls[] = {
|
||||
AD1836_ADC_SWITCH(1),
|
||||
AD1836_ADC_SWITCH(2),
|
||||
AD1836_ADC_SWITCH(3),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("ADC1IN"),
|
||||
SND_SOC_DAPM_INPUT("ADC2IN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad183x_adc_routes[] = {
|
||||
{ "ADC", NULL, "ADC1IN" },
|
||||
{ "ADC", NULL, "ADC2IN" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ad183x_controls[] = {
|
||||
/* ADC high-pass filter */
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1,
|
||||
AD1836_ADC_HIGHPASS_FILTER, 1, 0),
|
||||
|
||||
/* DAC de-emphasis */
|
||||
SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1,
|
||||
AD1836_DAC_POWERDOWN, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1,
|
||||
AD1836_ADC_POWERDOWN, 1, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad183x_dapm_routes[] = {
|
||||
{ "DAC", NULL, "ADC_PWR" },
|
||||
{ "ADC", NULL, "ADC_PWR" },
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0);
|
||||
|
||||
static const struct snd_kcontrol_new ad1836_controls[] = {
|
||||
SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0,
|
||||
ad1836_in_tlv),
|
||||
};
|
||||
|
||||
/*
|
||||
* DAI ops entries
|
||||
*/
|
||||
|
||||
static int ad1836_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
/* at present, we support adc aux mode to interface with
|
||||
* blackfin sport tdm mode
|
||||
*/
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
/* ALCLK,ABCLK are both output, AD1836 can only be master */
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad1836_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec);
|
||||
int word_len = 0;
|
||||
|
||||
/* bit size */
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
word_len = AD1836_WORD_LEN_16;
|
||||
break;
|
||||
case 20:
|
||||
word_len = AD1836_WORD_LEN_20;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
word_len = AD1836_WORD_LEN_24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,
|
||||
AD1836_DAC_WORD_LEN_MASK,
|
||||
word_len << AD1836_DAC_WORD_LEN_OFFSET);
|
||||
|
||||
regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
|
||||
AD1836_ADC_WORD_LEN_MASK,
|
||||
word_len << AD1836_ADC_WORD_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ad1836_dai_ops = {
|
||||
.hw_params = ad1836_hw_params,
|
||||
.set_fmt = ad1836_set_dai_fmt,
|
||||
};
|
||||
|
||||
#define AD183X_DAI(_name, num_dacs, num_adcs) \
|
||||
{ \
|
||||
.name = _name "-hifi", \
|
||||
.playback = { \
|
||||
.stream_name = "Playback", \
|
||||
.channels_min = 2, \
|
||||
.channels_max = (num_dacs) * 2, \
|
||||
.rates = SNDRV_PCM_RATE_48000, \
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
|
||||
}, \
|
||||
.capture = { \
|
||||
.stream_name = "Capture", \
|
||||
.channels_min = 2, \
|
||||
.channels_max = (num_adcs) * 2, \
|
||||
.rates = SNDRV_PCM_RATE_48000, \
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
|
||||
}, \
|
||||
.ops = &ad1836_dai_ops, \
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver ad183x_dais[] = {
|
||||
[AD1835] = AD183X_DAI("ad1835", 4, 1),
|
||||
[AD1836] = AD183X_DAI("ad1836", 3, 2),
|
||||
[AD1838] = AD183X_DAI("ad1838", 3, 1),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ad1836_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
|
||||
/* reset clock control mode */
|
||||
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
|
||||
AD1836_ADC_SERFMT_MASK, 0);
|
||||
}
|
||||
|
||||
static int ad1836_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
|
||||
/* restore clock control mode */
|
||||
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
|
||||
AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
|
||||
}
|
||||
#else
|
||||
#define ad1836_suspend NULL
|
||||
#define ad1836_resume NULL
|
||||
#endif
|
||||
|
||||
static int ad1836_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
int num_dacs, num_adcs;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
|
||||
num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
|
||||
|
||||
/* default setting for ad1836 */
|
||||
/* de-emphasis: 48kHz, power-on dac */
|
||||
regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300);
|
||||
/* unmute dac channels */
|
||||
regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0);
|
||||
/* high-pass filter enable, power-on adc */
|
||||
regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100);
|
||||
/* unmute adc channles, adc aux mode */
|
||||
regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180);
|
||||
/* volume */
|
||||
for (i = 1; i <= num_dacs; ++i) {
|
||||
regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF);
|
||||
regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF);
|
||||
}
|
||||
|
||||
if (ad1836->type == AD1836) {
|
||||
/* left/right diff:PGA/MUX */
|
||||
regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);
|
||||
ret = snd_soc_add_codec_controls(codec, ad1836_controls,
|
||||
ARRAY_SIZE(ad1836_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);
|
||||
}
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, ad183x_adc_controls, num_adcs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ad1836_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
|
||||
/* reset clock control mode */
|
||||
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
|
||||
AD1836_ADC_SERFMT_MASK, 0);
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
|
||||
.probe = ad1836_probe,
|
||||
.remove = ad1836_remove,
|
||||
.suspend = ad1836_suspend,
|
||||
.resume = ad1836_resume,
|
||||
|
||||
.controls = ad183x_controls,
|
||||
.num_controls = ARRAY_SIZE(ad183x_controls),
|
||||
.dapm_widgets = ad183x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
|
||||
.dapm_routes = ad183x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct reg_default ad1836_reg_defaults[] = {
|
||||
{ AD1836_DAC_CTRL1, 0x0000 },
|
||||
{ AD1836_DAC_CTRL2, 0x0000 },
|
||||
{ AD1836_DAC_L_VOL(0), 0x0000 },
|
||||
{ AD1836_DAC_R_VOL(0), 0x0000 },
|
||||
{ AD1836_DAC_L_VOL(1), 0x0000 },
|
||||
{ AD1836_DAC_R_VOL(1), 0x0000 },
|
||||
{ AD1836_DAC_L_VOL(2), 0x0000 },
|
||||
{ AD1836_DAC_R_VOL(2), 0x0000 },
|
||||
{ AD1836_DAC_L_VOL(3), 0x0000 },
|
||||
{ AD1836_DAC_R_VOL(3), 0x0000 },
|
||||
{ AD1836_ADC_CTRL1, 0x0000 },
|
||||
{ AD1836_ADC_CTRL2, 0x0000 },
|
||||
{ AD1836_ADC_CTRL3, 0x0000 },
|
||||
};
|
||||
|
||||
static const struct regmap_config ad1836_regmap_config = {
|
||||
.val_bits = 12,
|
||||
.reg_bits = 4,
|
||||
.read_flag_mask = 0x08,
|
||||
|
||||
.max_register = AD1836_ADC_CTRL3,
|
||||
.reg_defaults = ad1836_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int ad1836_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad1836_priv *ad1836;
|
||||
int ret;
|
||||
|
||||
ad1836 = devm_kzalloc(&spi->dev, sizeof(struct ad1836_priv),
|
||||
GFP_KERNEL);
|
||||
if (ad1836 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config);
|
||||
if (IS_ERR(ad1836->regmap))
|
||||
return PTR_ERR(ad1836->regmap);
|
||||
|
||||
ad1836->type = spi_get_device_id(spi)->driver_data;
|
||||
|
||||
spi_set_drvdata(spi, ad1836);
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad1836_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad1836_ids[] = {
|
||||
{ "ad1835", AD1835 },
|
||||
{ "ad1836", AD1836 },
|
||||
{ "ad1837", AD1835 },
|
||||
{ "ad1838", AD1838 },
|
||||
{ "ad1839", AD1838 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad1836_ids);
|
||||
|
||||
static struct spi_driver ad1836_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad1836",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad1836_spi_probe,
|
||||
.remove = ad1836_spi_remove,
|
||||
.id_table = ad1836_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(ad1836_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad1836 driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
51
sound/soc/codecs/ad1836.h
Normal file
51
sound/soc/codecs/ad1836.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Audio Codec driver supporting:
|
||||
* AD1835A, AD1836, AD1837A, AD1838A, AD1839A
|
||||
*
|
||||
* Copyright 2009-2011 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef __AD1836_H__
|
||||
#define __AD1836_H__
|
||||
|
||||
#define AD1836_DAC_CTRL1 0
|
||||
#define AD1836_DAC_POWERDOWN 2
|
||||
#define AD1836_DAC_SERFMT_MASK 0xE0
|
||||
#define AD1836_DAC_SERFMT_PCK256 (0x4 << 5)
|
||||
#define AD1836_DAC_SERFMT_PCK128 (0x5 << 5)
|
||||
#define AD1836_DAC_WORD_LEN_MASK 0x18
|
||||
#define AD1836_DAC_WORD_LEN_OFFSET 3
|
||||
|
||||
#define AD1836_DAC_CTRL2 1
|
||||
|
||||
/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit
|
||||
* for the first ADC/DAC */
|
||||
#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2)
|
||||
#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1)
|
||||
|
||||
#define AD1836_DAC_L_VOL(x) ((x) * 2)
|
||||
#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2))
|
||||
|
||||
#define AD1836_ADC_CTRL1 12
|
||||
#define AD1836_ADC_POWERDOWN 7
|
||||
#define AD1836_ADC_HIGHPASS_FILTER 8
|
||||
|
||||
#define AD1836_ADC_CTRL2 13
|
||||
#define AD1836_ADC_WORD_LEN_MASK 0x30
|
||||
#define AD1836_ADC_WORD_OFFSET 4
|
||||
#define AD1836_ADC_SERFMT_MASK (7 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6)
|
||||
#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6)
|
||||
#define AD1836_ADC_AUX (0x6 << 6)
|
||||
|
||||
#define AD1836_ADC_CTRL3 14
|
||||
|
||||
#define AD1836_NUM_REGS 16
|
||||
|
||||
#define AD1836_WORD_LEN_24 0x0
|
||||
#define AD1836_WORD_LEN_20 0x1
|
||||
#define AD1836_WORD_LEN_16 0x2
|
||||
|
||||
#endif
|
||||
54
sound/soc/codecs/ad193x-i2c.c
Normal file
54
sound/soc/codecs/ad193x-i2c.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* AD1936/AD1937 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
static const struct i2c_device_id ad193x_id[] = {
|
||||
{ "ad1936", 0 },
|
||||
{ "ad1937", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad193x_id);
|
||||
|
||||
static int ad193x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = ad193x_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 8;
|
||||
|
||||
return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config));
|
||||
}
|
||||
|
||||
static int ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver ad193x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
},
|
||||
.probe = ad193x_i2c_probe,
|
||||
.remove = ad193x_i2c_remove,
|
||||
.id_table = ad193x_id,
|
||||
};
|
||||
module_i2c_driver(ad193x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
48
sound/soc/codecs/ad193x-spi.c
Normal file
48
sound/soc/codecs/ad193x-spi.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* AD1938/AD1939 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
static int ad193x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = ad193x_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
config.read_flag_mask = 0x09;
|
||||
config.write_flag_mask = 0x08;
|
||||
|
||||
return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
|
||||
}
|
||||
|
||||
static int ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad193x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad193x_spi_probe,
|
||||
.remove = ad193x_spi_remove,
|
||||
};
|
||||
module_spi_driver(ad193x_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
388
sound/soc/codecs/ad193x.c
Normal file
388
sound/soc/codecs/ad193x.c
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* AD193X Audio Codec driver supporting AD1936/7/8/9
|
||||
*
|
||||
* Copyright 2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
/* codec private data */
|
||||
struct ad193x_priv {
|
||||
struct regmap *regmap;
|
||||
int sysclk;
|
||||
};
|
||||
|
||||
/*
|
||||
* AD193X volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
|
||||
ad193x_deemp);
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
|
||||
|
||||
static const struct snd_kcontrol_new ad193x_snd_controls[] = {
|
||||
/* DAC volume control */
|
||||
SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL,
|
||||
AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL,
|
||||
AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL,
|
||||
AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,
|
||||
AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),
|
||||
|
||||
/* ADC switch control */
|
||||
SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
|
||||
AD193X_ADCR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
|
||||
AD193X_ADCR2_MUTE, 1, 1),
|
||||
|
||||
/* DAC switch control */
|
||||
SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,
|
||||
AD193X_DACR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE,
|
||||
AD193X_DACR2_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE,
|
||||
AD193X_DACR3_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,
|
||||
AD193X_DACR4_MUTE, 1, 1),
|
||||
|
||||
/* ADC high-pass filter */
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,
|
||||
AD193X_ADC_HIGHPASS_FILTER, 1, 0),
|
||||
|
||||
/* DAC de-emphasis */
|
||||
SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC4OUT"),
|
||||
SND_SOC_DAPM_INPUT("ADC1IN"),
|
||||
SND_SOC_DAPM_INPUT("ADC2IN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths[] = {
|
||||
{ "DAC", NULL, "SYSCLK" },
|
||||
{ "ADC", NULL, "SYSCLK" },
|
||||
{ "DAC", NULL, "ADC_PWR" },
|
||||
{ "ADC", NULL, "ADC_PWR" },
|
||||
{ "DAC1OUT", NULL, "DAC" },
|
||||
{ "DAC2OUT", NULL, "DAC" },
|
||||
{ "DAC3OUT", NULL, "DAC" },
|
||||
{ "DAC4OUT", NULL, "DAC" },
|
||||
{ "ADC", NULL, "ADC1IN" },
|
||||
{ "ADC", NULL, "ADC2IN" },
|
||||
{ "SYSCLK", NULL, "PLL_PWR" },
|
||||
};
|
||||
|
||||
/*
|
||||
* DAI ops entries
|
||||
*/
|
||||
|
||||
static int ad193x_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
||||
if (mute)
|
||||
regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
|
||||
AD193X_DAC_MASTER_MUTE,
|
||||
AD193X_DAC_MASTER_MUTE);
|
||||
else
|
||||
regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
|
||||
AD193X_DAC_MASTER_MUTE, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots, int width)
|
||||
{
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
|
||||
unsigned int channels;
|
||||
|
||||
switch (slots) {
|
||||
case 2:
|
||||
channels = AD193X_2_CHANNELS;
|
||||
break;
|
||||
case 4:
|
||||
channels = AD193X_4_CHANNELS;
|
||||
break;
|
||||
case 8:
|
||||
channels = AD193X_8_CHANNELS;
|
||||
break;
|
||||
case 16:
|
||||
channels = AD193X_16_CHANNELS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
|
||||
AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);
|
||||
regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
|
||||
AD193X_ADC_CHAN_MASK, channels << AD193X_ADC_CHAN_SHFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec_dai->codec);
|
||||
unsigned int adc_serfmt = 0;
|
||||
unsigned int adc_fmt = 0;
|
||||
unsigned int dac_fmt = 0;
|
||||
|
||||
/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
|
||||
* with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
|
||||
*/
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
adc_serfmt |= AD193X_ADC_SERFMT_TDM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
adc_serfmt |= AD193X_ADC_SERFMT_AUX;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
|
||||
adc_fmt |= AD193X_ADC_LEFT_HIGH;
|
||||
dac_fmt |= AD193X_DAC_LEFT_HIGH;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
|
||||
adc_fmt |= AD193X_ADC_BCLK_INV;
|
||||
dac_fmt |= AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
|
||||
adc_fmt |= AD193X_ADC_LEFT_HIGH;
|
||||
adc_fmt |= AD193X_ADC_BCLK_INV;
|
||||
dac_fmt |= AD193X_DAC_LEFT_HIGH;
|
||||
dac_fmt |= AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
|
||||
adc_fmt |= AD193X_ADC_LCR_MASTER;
|
||||
adc_fmt |= AD193X_ADC_BCLK_MASTER;
|
||||
dac_fmt |= AD193X_DAC_LCR_MASTER;
|
||||
dac_fmt |= AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
|
||||
adc_fmt |= AD193X_ADC_LCR_MASTER;
|
||||
dac_fmt |= AD193X_DAC_LCR_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
|
||||
adc_fmt |= AD193X_ADC_BCLK_MASTER;
|
||||
dac_fmt |= AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
|
||||
AD193X_ADC_SERFMT_MASK, adc_serfmt);
|
||||
regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
|
||||
AD193X_ADC_FMT_MASK, adc_fmt);
|
||||
regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
|
||||
AD193X_DAC_FMT_MASK, dac_fmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
switch (freq) {
|
||||
case 12288000:
|
||||
case 18432000:
|
||||
case 24576000:
|
||||
case 36864000:
|
||||
ad193x->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ad193x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int word_len = 0, master_rate = 0;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* bit size */
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
word_len = 3;
|
||||
break;
|
||||
case 20:
|
||||
word_len = 1;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
word_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ad193x->sysclk) {
|
||||
case 12288000:
|
||||
master_rate = AD193X_PLL_INPUT_256;
|
||||
break;
|
||||
case 18432000:
|
||||
master_rate = AD193X_PLL_INPUT_384;
|
||||
break;
|
||||
case 24576000:
|
||||
master_rate = AD193X_PLL_INPUT_512;
|
||||
break;
|
||||
case 36864000:
|
||||
master_rate = AD193X_PLL_INPUT_768;
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,
|
||||
AD193X_PLL_INPUT_MASK, master_rate);
|
||||
|
||||
regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
|
||||
AD193X_DAC_WORD_LEN_MASK,
|
||||
word_len << AD193X_DAC_WORD_LEN_SHFT);
|
||||
|
||||
regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
|
||||
AD193X_ADC_WORD_LEN_MASK, word_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ad193x_dai_ops = {
|
||||
.hw_params = ad193x_hw_params,
|
||||
.digital_mute = ad193x_mute,
|
||||
.set_tdm_slot = ad193x_set_tdm_slot,
|
||||
.set_sysclk = ad193x_set_dai_sysclk,
|
||||
.set_fmt = ad193x_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
static struct snd_soc_dai_driver ad193x_dai = {
|
||||
.name = "ad193x-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
|
||||
static int ad193x_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* default setting for ad193x */
|
||||
|
||||
/* unmute dac channels */
|
||||
regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
|
||||
/* de-emphasis: 48kHz, powedown dac */
|
||||
regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
|
||||
/* powerdown dac, dac in tdm mode */
|
||||
regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41);
|
||||
/* high-pass filter enable */
|
||||
regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
|
||||
/* sata delay=1, adc aux mode */
|
||||
regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
|
||||
/* pll input: mclki/xi */
|
||||
regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
|
||||
regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
|
||||
.probe = ad193x_codec_probe,
|
||||
.controls = ad193x_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ad193x_snd_controls),
|
||||
.dapm_widgets = ad193x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets),
|
||||
.dapm_routes = audio_paths,
|
||||
.num_dapm_routes = ARRAY_SIZE(audio_paths),
|
||||
};
|
||||
|
||||
static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct regmap_config ad193x_regmap_config = {
|
||||
.max_register = AD193X_NUM_REGS - 1,
|
||||
.volatile_reg = adau193x_reg_volatile,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad193x_regmap_config);
|
||||
|
||||
int ad193x_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct ad193x_priv *ad193x;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad193x->regmap = regmap;
|
||||
|
||||
dev_set_drvdata(dev, ad193x);
|
||||
|
||||
return snd_soc_register_codec(dev, &soc_codec_dev_ad193x,
|
||||
&ad193x_dai, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ad193x_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad193x driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
92
sound/soc/codecs/ad193x.h
Normal file
92
sound/soc/codecs/ad193x.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* AD193X Audio Codec driver
|
||||
*
|
||||
* Copyright 2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef __AD193X_H__
|
||||
#define __AD193X_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device;
|
||||
|
||||
extern const struct regmap_config ad193x_regmap_config;
|
||||
int ad193x_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
#define AD193X_PLL_CLK_CTRL0 0x00
|
||||
#define AD193X_PLL_POWERDOWN 0x01
|
||||
#define AD193X_PLL_INPUT_MASK 0x6
|
||||
#define AD193X_PLL_INPUT_256 (0 << 1)
|
||||
#define AD193X_PLL_INPUT_384 (1 << 1)
|
||||
#define AD193X_PLL_INPUT_512 (2 << 1)
|
||||
#define AD193X_PLL_INPUT_768 (3 << 1)
|
||||
#define AD193X_PLL_CLK_CTRL1 0x01
|
||||
#define AD193X_DAC_CTRL0 0x02
|
||||
#define AD193X_DAC_POWERDOWN 0x01
|
||||
#define AD193X_DAC_SERFMT_MASK 0xC0
|
||||
#define AD193X_DAC_SERFMT_STEREO (0 << 6)
|
||||
#define AD193X_DAC_SERFMT_TDM (1 << 6)
|
||||
#define AD193X_DAC_CTRL1 0x03
|
||||
#define AD193X_DAC_CHAN_SHFT 1
|
||||
#define AD193X_DAC_CHAN_MASK (3 << AD193X_DAC_CHAN_SHFT)
|
||||
#define AD193X_DAC_LCR_MASTER (1 << 4)
|
||||
#define AD193X_DAC_BCLK_MASTER (1 << 5)
|
||||
#define AD193X_DAC_LEFT_HIGH (1 << 3)
|
||||
#define AD193X_DAC_BCLK_INV (1 << 7)
|
||||
#define AD193X_DAC_FMT_MASK (AD193X_DAC_LCR_MASTER | \
|
||||
AD193X_DAC_BCLK_MASTER | AD193X_DAC_LEFT_HIGH | AD193X_DAC_BCLK_INV)
|
||||
#define AD193X_DAC_CTRL2 0x04
|
||||
#define AD193X_DAC_WORD_LEN_SHFT 3
|
||||
#define AD193X_DAC_WORD_LEN_MASK 0x18
|
||||
#define AD193X_DAC_MASTER_MUTE 1
|
||||
#define AD193X_DAC_CHNL_MUTE 0x05
|
||||
#define AD193X_DACL1_MUTE 0
|
||||
#define AD193X_DACR1_MUTE 1
|
||||
#define AD193X_DACL2_MUTE 2
|
||||
#define AD193X_DACR2_MUTE 3
|
||||
#define AD193X_DACL3_MUTE 4
|
||||
#define AD193X_DACR3_MUTE 5
|
||||
#define AD193X_DACL4_MUTE 6
|
||||
#define AD193X_DACR4_MUTE 7
|
||||
#define AD193X_DAC_L1_VOL 0x06
|
||||
#define AD193X_DAC_R1_VOL 0x07
|
||||
#define AD193X_DAC_L2_VOL 0x08
|
||||
#define AD193X_DAC_R2_VOL 0x09
|
||||
#define AD193X_DAC_L3_VOL 0x0a
|
||||
#define AD193X_DAC_R3_VOL 0x0b
|
||||
#define AD193X_DAC_L4_VOL 0x0c
|
||||
#define AD193X_DAC_R4_VOL 0x0d
|
||||
#define AD193X_ADC_CTRL0 0x0e
|
||||
#define AD193X_ADC_POWERDOWN 0x01
|
||||
#define AD193X_ADC_HIGHPASS_FILTER 1
|
||||
#define AD193X_ADCL1_MUTE 2
|
||||
#define AD193X_ADCR1_MUTE 3
|
||||
#define AD193X_ADCL2_MUTE 4
|
||||
#define AD193X_ADCR2_MUTE 5
|
||||
#define AD193X_ADC_CTRL1 0x0f
|
||||
#define AD193X_ADC_SERFMT_MASK 0x60
|
||||
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
|
||||
#define AD193X_ADC_SERFMT_TDM (1 << 5)
|
||||
#define AD193X_ADC_SERFMT_AUX (2 << 5)
|
||||
#define AD193X_ADC_WORD_LEN_MASK 0x3
|
||||
#define AD193X_ADC_CTRL2 0x10
|
||||
#define AD193X_ADC_CHAN_SHFT 4
|
||||
#define AD193X_ADC_CHAN_MASK (3 << AD193X_ADC_CHAN_SHFT)
|
||||
#define AD193X_ADC_LCR_MASTER (1 << 3)
|
||||
#define AD193X_ADC_BCLK_MASTER (1 << 6)
|
||||
#define AD193X_ADC_LEFT_HIGH (1 << 2)
|
||||
#define AD193X_ADC_BCLK_INV (1 << 1)
|
||||
#define AD193X_ADC_FMT_MASK (AD193X_ADC_LCR_MASTER | \
|
||||
AD193X_ADC_BCLK_MASTER | AD193X_ADC_LEFT_HIGH | AD193X_ADC_BCLK_INV)
|
||||
|
||||
#define AD193X_2_CHANNELS 0
|
||||
#define AD193X_4_CHANNELS 1
|
||||
#define AD193X_8_CHANNELS 2
|
||||
#define AD193X_16_CHANNELS 3
|
||||
|
||||
#define AD193X_NUM_REGS 17
|
||||
|
||||
#endif
|
||||
326
sound/soc/codecs/ad1980.c
Normal file
326
sound/soc/codecs/ad1980.c
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* ad1980.c -- ALSA Soc AD1980 codec support
|
||||
*
|
||||
* Copyright: Analog Device Inc.
|
||||
* Author: Roy Huang <roy.huang@analog.com>
|
||||
* Cliff Cai <cliff.cai@analog.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
*
|
||||
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
* by ADI now.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad1980.h"
|
||||
|
||||
/*
|
||||
* AD1980 register cache
|
||||
*/
|
||||
static const u16 ad1980_reg[] = {
|
||||
0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */
|
||||
0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */
|
||||
0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
|
||||
0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
|
||||
0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
|
||||
0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
|
||||
0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
|
||||
0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */
|
||||
};
|
||||
|
||||
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
|
||||
"Stereo Mix", "Mono Mix", "Phone"};
|
||||
|
||||
static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src,
|
||||
AC97_REC_SEL, 8, 0, ad1980_rec_sel);
|
||||
|
||||
static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
|
||||
SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
|
||||
SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
|
||||
|
||||
SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
|
||||
SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
|
||||
|
||||
SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
|
||||
SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
|
||||
|
||||
SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0),
|
||||
SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1),
|
||||
|
||||
SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
|
||||
SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
|
||||
|
||||
SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1),
|
||||
SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1),
|
||||
|
||||
SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1),
|
||||
SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
|
||||
|
||||
SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0),
|
||||
SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0),
|
||||
|
||||
SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
|
||||
SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
|
||||
|
||||
SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1),
|
||||
SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1),
|
||||
|
||||
SOC_ENUM("Capture Source", ad1980_cap_src),
|
||||
|
||||
SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("MIC1"),
|
||||
SND_SOC_DAPM_INPUT("MIC2"),
|
||||
SND_SOC_DAPM_INPUT("CD_L"),
|
||||
SND_SOC_DAPM_INPUT("CD_R"),
|
||||
SND_SOC_DAPM_INPUT("AUX_L"),
|
||||
SND_SOC_DAPM_INPUT("AUX_R"),
|
||||
SND_SOC_DAPM_INPUT("LINE_IN_L"),
|
||||
SND_SOC_DAPM_INPUT("LINE_IN_R"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LFE_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("CENTER_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("LINE_OUT_L"),
|
||||
SND_SOC_DAPM_OUTPUT("LINE_OUT_R"),
|
||||
SND_SOC_DAPM_OUTPUT("MONO_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("HP_OUT_L"),
|
||||
SND_SOC_DAPM_OUTPUT("HP_OUT_R"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
|
||||
{ "Capture", NULL, "MIC1" },
|
||||
{ "Capture", NULL, "MIC2" },
|
||||
{ "Capture", NULL, "CD_L" },
|
||||
{ "Capture", NULL, "CD_R" },
|
||||
{ "Capture", NULL, "AUX_L" },
|
||||
{ "Capture", NULL, "AUX_R" },
|
||||
{ "Capture", NULL, "LINE_IN_L" },
|
||||
{ "Capture", NULL, "LINE_IN_R" },
|
||||
|
||||
{ "LFE_OUT", NULL, "Playback" },
|
||||
{ "CENTER_OUT", NULL, "Playback" },
|
||||
{ "LINE_OUT_L", NULL, "Playback" },
|
||||
{ "LINE_OUT_R", NULL, "Playback" },
|
||||
{ "MONO_OUT", NULL, "Playback" },
|
||||
{ "HP_OUT_L", NULL, "Playback" },
|
||||
{ "HP_OUT_R", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static unsigned int ac97_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
switch (reg) {
|
||||
case AC97_RESET:
|
||||
case AC97_INT_PAGING:
|
||||
case AC97_POWERDOWN:
|
||||
case AC97_EXTENDED_STATUS:
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
return soc_ac97_ops->read(codec->ac97, reg);
|
||||
default:
|
||||
reg = reg >> 1;
|
||||
|
||||
if (reg >= ARRAY_SIZE(ad1980_reg))
|
||||
return -EINVAL;
|
||||
|
||||
return cache[reg];
|
||||
}
|
||||
}
|
||||
|
||||
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
soc_ac97_ops->write(codec->ac97, reg, val);
|
||||
reg = reg >> 1;
|
||||
if (reg < ARRAY_SIZE(ad1980_reg))
|
||||
cache[reg] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver ad1980_dai = {
|
||||
.name = "ad1980-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 6,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SND_SOC_STD_AC97_FMTS, },
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SND_SOC_STD_AC97_FMTS, },
|
||||
};
|
||||
|
||||
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
|
||||
{
|
||||
unsigned int retry_cnt = 0;
|
||||
|
||||
do {
|
||||
if (try_warm && soc_ac97_ops->warm_reset) {
|
||||
soc_ac97_ops->warm_reset(codec->ac97);
|
||||
if (ac97_read(codec, AC97_RESET) == 0x0090)
|
||||
return 1;
|
||||
}
|
||||
|
||||
soc_ac97_ops->reset(codec->ac97);
|
||||
/*
|
||||
* Set bit 16slot in register 74h, then every slot will has only
|
||||
* 16 bits. This command is sent out in 20bit mode, in which
|
||||
* case the first nibble of data is eaten by the addr. (Tag is
|
||||
* always 16 bit)
|
||||
*/
|
||||
ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
|
||||
|
||||
if (ac97_read(codec, AC97_RESET) == 0x0090)
|
||||
return 0;
|
||||
} while (retry_cnt++ < 10);
|
||||
|
||||
printk(KERN_ERR "AD1980 AC97 reset failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ad1980_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
u16 vendor_id2;
|
||||
u16 ext_status;
|
||||
|
||||
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
|
||||
|
||||
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad1980_reset(codec, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
|
||||
goto reset_err;
|
||||
}
|
||||
|
||||
/* Read out vendor ID to make sure it is ad1980 */
|
||||
if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
}
|
||||
|
||||
vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
|
||||
|
||||
if (vendor_id2 != 0x5370) {
|
||||
if (vendor_id2 != 0x5374) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
} else {
|
||||
printk(KERN_WARNING "ad1980: "
|
||||
"Found AD1981 - only 2/2 IN/OUT Channels "
|
||||
"supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* unmute captures and playbacks volume */
|
||||
ac97_write(codec, AC97_MASTER, 0x0000);
|
||||
ac97_write(codec, AC97_PCM, 0x0000);
|
||||
ac97_write(codec, AC97_REC_GAIN, 0x0000);
|
||||
ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
|
||||
ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
|
||||
|
||||
/*power on LFE/CENTER/Surround DACs*/
|
||||
ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
|
||||
ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
|
||||
|
||||
snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
|
||||
ARRAY_SIZE(ad1980_snd_ac97_controls));
|
||||
|
||||
return 0;
|
||||
|
||||
reset_err:
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad1980_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
|
||||
.probe = ad1980_soc_probe,
|
||||
.remove = ad1980_soc_remove,
|
||||
.reg_cache_size = ARRAY_SIZE(ad1980_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = ad1980_reg,
|
||||
.reg_cache_step = 2,
|
||||
.write = ac97_write,
|
||||
.read = ac97_read,
|
||||
|
||||
.dapm_widgets = ad1980_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
|
||||
.dapm_routes = ad1980_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
|
||||
};
|
||||
|
||||
static int ad1980_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ad1980, &ad1980_dai, 1);
|
||||
}
|
||||
|
||||
static int ad1980_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ad1980_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ad1980",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ad1980_probe,
|
||||
.remove = ad1980_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ad1980_codec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
|
||||
MODULE_AUTHOR("Roy Huang, Cliff Cai");
|
||||
MODULE_LICENSE("GPL");
|
||||
26
sound/soc/codecs/ad1980.h
Normal file
26
sound/soc/codecs/ad1980.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* ad1980.h -- ad1980 Soc Audio driver
|
||||
*
|
||||
* WARNING:
|
||||
*
|
||||
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
* by ADI now.
|
||||
*/
|
||||
|
||||
#ifndef _AD1980_H
|
||||
#define _AD1980_H
|
||||
/* Bit definition of Power-Down Control/Status Register */
|
||||
#define ADC 0x0001
|
||||
#define DAC 0x0002
|
||||
#define ANL 0x0004
|
||||
#define REF 0x0008
|
||||
#define PR0 0x0100
|
||||
#define PR1 0x0200
|
||||
#define PR2 0x0400
|
||||
#define PR3 0x0800
|
||||
#define PR4 0x1000
|
||||
#define PR5 0x2000
|
||||
#define PR6 0x4000
|
||||
|
||||
#endif
|
||||
90
sound/soc/codecs/ad73311.c
Normal file
90
sound/soc/codecs/ad73311.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* ad73311.c -- ALSA Soc AD73311 codec support
|
||||
*
|
||||
* Copyright: Analog Device Inc.
|
||||
* Author: Cliff Cai <cliff.cai@analog.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad73311.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("VINP"),
|
||||
SND_SOC_DAPM_INPUT("VINN"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTN"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTP"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad73311_dapm_routes[] = {
|
||||
{ "Capture", NULL, "VINP" },
|
||||
{ "Capture", NULL, "VINN" },
|
||||
|
||||
{ "VOUTN", NULL, "Playback" },
|
||||
{ "VOUTP", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ad73311_dai = {
|
||||
.name = "ad73311-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
|
||||
.dapm_widgets = ad73311_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
|
||||
.dapm_routes = ad73311_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
|
||||
};
|
||||
|
||||
static int ad73311_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ad73311, &ad73311_dai, 1);
|
||||
}
|
||||
|
||||
static int ad73311_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ad73311_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ad73311",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ad73311_probe,
|
||||
.remove = ad73311_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ad73311_codec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad73311 driver");
|
||||
MODULE_AUTHOR("Cliff Cai ");
|
||||
MODULE_LICENSE("GPL");
|
||||
88
sound/soc/codecs/ad73311.h
Normal file
88
sound/soc/codecs/ad73311.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* File: sound/soc/codec/ad73311.h
|
||||
* Based on:
|
||||
* Author: Cliff Cai <cliff.cai@analog.com>
|
||||
*
|
||||
* Created: Thur Sep 25, 2008
|
||||
* Description: definitions for AD73311 registers
|
||||
*
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __AD73311_H__
|
||||
#define __AD73311_H__
|
||||
|
||||
#define AD_CONTROL 0x8000
|
||||
#define AD_DATA 0x0000
|
||||
#define AD_READ 0x4000
|
||||
#define AD_WRITE 0x0000
|
||||
|
||||
/* Control register A */
|
||||
#define CTRL_REG_A (0 << 8)
|
||||
|
||||
#define REGA_MODE_PRO 0x00
|
||||
#define REGA_MODE_DATA 0x01
|
||||
#define REGA_MODE_MIXED 0x03
|
||||
#define REGA_DLB 0x04
|
||||
#define REGA_SLB 0x08
|
||||
#define REGA_DEVC(x) ((x & 0x7) << 4)
|
||||
#define REGA_RESET 0x80
|
||||
|
||||
/* Control register B */
|
||||
#define CTRL_REG_B (1 << 8)
|
||||
|
||||
#define REGB_DIRATE(x) (x & 0x3)
|
||||
#define REGB_SCDIV(x) ((x & 0x3) << 2)
|
||||
#define REGB_MCDIV(x) ((x & 0x7) << 4)
|
||||
#define REGB_CEE (1 << 7)
|
||||
|
||||
/* Control register C */
|
||||
#define CTRL_REG_C (2 << 8)
|
||||
|
||||
#define REGC_PUDEV (1 << 0)
|
||||
#define REGC_PUADC (1 << 3)
|
||||
#define REGC_PUDAC (1 << 4)
|
||||
#define REGC_PUREF (1 << 5)
|
||||
#define REGC_REFUSE (1 << 6)
|
||||
|
||||
/* Control register D */
|
||||
#define CTRL_REG_D (3 << 8)
|
||||
|
||||
#define REGD_IGS(x) (x & 0x7)
|
||||
#define REGD_RMOD (1 << 3)
|
||||
#define REGD_OGS(x) ((x & 0x7) << 4)
|
||||
#define REGD_MUTE (1 << 7)
|
||||
|
||||
/* Control register E */
|
||||
#define CTRL_REG_E (4 << 8)
|
||||
|
||||
#define REGE_DA(x) (x & 0x1f)
|
||||
#define REGE_IBYP (1 << 5)
|
||||
|
||||
/* Control register F */
|
||||
#define CTRL_REG_F (5 << 8)
|
||||
|
||||
#define REGF_SEEN (1 << 5)
|
||||
#define REGF_INV (1 << 6)
|
||||
#define REGF_ALB (1 << 7)
|
||||
|
||||
#endif
|
||||
1549
sound/soc/codecs/adau1373.c
Normal file
1549
sound/soc/codecs/adau1373.c
Normal file
File diff suppressed because it is too large
Load diff
29
sound/soc/codecs/adau1373.h
Normal file
29
sound/soc/codecs/adau1373.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef __ADAU1373_H__
|
||||
#define __ADAU1373_H__
|
||||
|
||||
enum adau1373_pll_src {
|
||||
ADAU1373_PLL_SRC_MCLK1 = 0,
|
||||
ADAU1373_PLL_SRC_BCLK1 = 1,
|
||||
ADAU1373_PLL_SRC_BCLK2 = 2,
|
||||
ADAU1373_PLL_SRC_BCLK3 = 3,
|
||||
ADAU1373_PLL_SRC_LRCLK1 = 4,
|
||||
ADAU1373_PLL_SRC_LRCLK2 = 5,
|
||||
ADAU1373_PLL_SRC_LRCLK3 = 6,
|
||||
ADAU1373_PLL_SRC_GPIO1 = 7,
|
||||
ADAU1373_PLL_SRC_GPIO2 = 8,
|
||||
ADAU1373_PLL_SRC_GPIO3 = 9,
|
||||
ADAU1373_PLL_SRC_GPIO4 = 10,
|
||||
ADAU1373_PLL_SRC_MCLK2 = 11,
|
||||
};
|
||||
|
||||
enum adau1373_pll {
|
||||
ADAU1373_PLL1 = 0,
|
||||
ADAU1373_PLL2 = 1,
|
||||
};
|
||||
|
||||
enum adau1373_clk_src {
|
||||
ADAU1373_CLK_SRC_PLL1 = 0,
|
||||
ADAU1373_CLK_SRC_PLL2 = 1,
|
||||
};
|
||||
|
||||
#endif
|
||||
761
sound/soc/codecs/adau1701.c
Normal file
761
sound/soc/codecs/adau1701.c
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
* Driver for ADAU1701 SigmaDSP processor
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
* based on an inital version by Cliff Cai <cliff.cai@analog.com>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau1701.h"
|
||||
|
||||
#define ADAU1701_DSPCTRL 0x081c
|
||||
#define ADAU1701_SEROCTL 0x081e
|
||||
#define ADAU1701_SERICTL 0x081f
|
||||
|
||||
#define ADAU1701_AUXNPOW 0x0822
|
||||
#define ADAU1701_PINCONF_0 0x0820
|
||||
#define ADAU1701_PINCONF_1 0x0821
|
||||
#define ADAU1701_AUXNPOW 0x0822
|
||||
|
||||
#define ADAU1701_OSCIPOW 0x0826
|
||||
#define ADAU1701_DACSET 0x0827
|
||||
|
||||
#define ADAU1701_MAX_REGISTER 0x0828
|
||||
|
||||
#define ADAU1701_DSPCTRL_CR (1 << 2)
|
||||
#define ADAU1701_DSPCTRL_DAM (1 << 3)
|
||||
#define ADAU1701_DSPCTRL_ADM (1 << 4)
|
||||
#define ADAU1701_DSPCTRL_SR_48 0x00
|
||||
#define ADAU1701_DSPCTRL_SR_96 0x01
|
||||
#define ADAU1701_DSPCTRL_SR_192 0x02
|
||||
#define ADAU1701_DSPCTRL_SR_MASK 0x03
|
||||
|
||||
#define ADAU1701_SEROCTL_INV_LRCLK 0x2000
|
||||
#define ADAU1701_SEROCTL_INV_BCLK 0x1000
|
||||
#define ADAU1701_SEROCTL_MASTER 0x0800
|
||||
|
||||
#define ADAU1701_SEROCTL_OBF16 0x0000
|
||||
#define ADAU1701_SEROCTL_OBF8 0x0200
|
||||
#define ADAU1701_SEROCTL_OBF4 0x0400
|
||||
#define ADAU1701_SEROCTL_OBF2 0x0600
|
||||
#define ADAU1701_SEROCTL_OBF_MASK 0x0600
|
||||
|
||||
#define ADAU1701_SEROCTL_OLF1024 0x0000
|
||||
#define ADAU1701_SEROCTL_OLF512 0x0080
|
||||
#define ADAU1701_SEROCTL_OLF256 0x0100
|
||||
#define ADAU1701_SEROCTL_OLF_MASK 0x0180
|
||||
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY1 0x0000
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY0 0x0004
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY8 0x0008
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY12 0x000c
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY16 0x0010
|
||||
#define ADAU1701_SEROCTL_MSB_DEALY_MASK 0x001c
|
||||
|
||||
#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000
|
||||
#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001
|
||||
#define ADAU1701_SEROCTL_WORD_LEN_16 0x0002
|
||||
#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003
|
||||
|
||||
#define ADAU1701_AUXNPOW_VBPD 0x40
|
||||
#define ADAU1701_AUXNPOW_VRPD 0x20
|
||||
|
||||
#define ADAU1701_SERICTL_I2S 0
|
||||
#define ADAU1701_SERICTL_LEFTJ 1
|
||||
#define ADAU1701_SERICTL_TDM 2
|
||||
#define ADAU1701_SERICTL_RIGHTJ_24 3
|
||||
#define ADAU1701_SERICTL_RIGHTJ_20 4
|
||||
#define ADAU1701_SERICTL_RIGHTJ_18 5
|
||||
#define ADAU1701_SERICTL_RIGHTJ_16 6
|
||||
#define ADAU1701_SERICTL_MODE_MASK 7
|
||||
#define ADAU1701_SERICTL_INV_BCLK BIT(3)
|
||||
#define ADAU1701_SERICTL_INV_LRCLK BIT(4)
|
||||
|
||||
#define ADAU1701_OSCIPOW_OPD 0x04
|
||||
#define ADAU1701_DACSET_DACINIT 1
|
||||
|
||||
#define ADAU1707_CLKDIV_UNSET (-1U)
|
||||
|
||||
#define ADAU1701_FIRMWARE "adau1701.bin"
|
||||
|
||||
struct adau1701 {
|
||||
int gpio_nreset;
|
||||
int gpio_pll_mode[2];
|
||||
unsigned int dai_fmt;
|
||||
unsigned int pll_clkdiv;
|
||||
unsigned int sysclk;
|
||||
struct regmap *regmap;
|
||||
u8 pin_config[12];
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1701_controls[] = {
|
||||
SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1),
|
||||
SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1),
|
||||
SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1),
|
||||
SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("OUT0"),
|
||||
SND_SOC_DAPM_OUTPUT("OUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("OUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("OUT3"),
|
||||
SND_SOC_DAPM_INPUT("IN0"),
|
||||
SND_SOC_DAPM_INPUT("IN1"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
|
||||
{ "OUT0", NULL, "DAC0" },
|
||||
{ "OUT1", NULL, "DAC1" },
|
||||
{ "OUT2", NULL, "DAC2" },
|
||||
{ "OUT3", NULL, "DAC3" },
|
||||
|
||||
{ "ADC", NULL, "IN0" },
|
||||
{ "ADC", NULL, "IN1" },
|
||||
};
|
||||
|
||||
static unsigned int adau1701_register_size(struct device *dev,
|
||||
unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1701_PINCONF_0:
|
||||
case ADAU1701_PINCONF_1:
|
||||
return 3;
|
||||
case ADAU1701_DSPCTRL:
|
||||
case ADAU1701_SEROCTL:
|
||||
case ADAU1701_AUXNPOW:
|
||||
case ADAU1701_OSCIPOW:
|
||||
case ADAU1701_DACSET:
|
||||
return 2;
|
||||
case ADAU1701_SERICTL:
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev_err(dev, "Unsupported register address: %d\n", reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1701_DACSET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int adau1701_reg_write(void *context, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
unsigned int i;
|
||||
unsigned int size;
|
||||
uint8_t buf[5];
|
||||
int ret;
|
||||
|
||||
size = adau1701_register_size(&client->dev, reg);
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = reg >> 8;
|
||||
buf[1] = reg & 0xff;
|
||||
|
||||
for (i = size + 1; i >= 2; --i) {
|
||||
buf[i] = value;
|
||||
value >>= 8;
|
||||
}
|
||||
|
||||
ret = i2c_master_send(client, buf, size + 2);
|
||||
if (ret == size + 2)
|
||||
return 0;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int adau1701_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *value)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i;
|
||||
unsigned int size;
|
||||
uint8_t send_buf[2], recv_buf[3];
|
||||
struct i2c_client *client = context;
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
size = adau1701_register_size(&client->dev, reg);
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
send_buf[0] = reg >> 8;
|
||||
send_buf[1] = reg & 0xff;
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].len = sizeof(send_buf);
|
||||
msgs[0].buf = send_buf;
|
||||
msgs[0].flags = 0;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].len = size;
|
||||
msgs[1].buf = recv_buf;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != ARRAY_SIZE(msgs))
|
||||
return -EIO;
|
||||
|
||||
*value = 0;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
*value <<= 8;
|
||||
*value |= recv_buf[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
|
||||
{
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *client = to_i2c_client(codec->dev);
|
||||
int ret;
|
||||
|
||||
if (clkdiv != ADAU1707_CLKDIV_UNSET &&
|
||||
gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
|
||||
gpio_is_valid(adau1701->gpio_pll_mode[1])) {
|
||||
switch (clkdiv) {
|
||||
case 64:
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
|
||||
break;
|
||||
case 256:
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
|
||||
break;
|
||||
case 384:
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
adau1701->pll_clkdiv = clkdiv;
|
||||
|
||||
if (gpio_is_valid(adau1701->gpio_nreset)) {
|
||||
gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
|
||||
/* minimum reset time is 20ns */
|
||||
udelay(1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_nreset, 1);
|
||||
/* power-up time may be as long as 85ms */
|
||||
mdelay(85);
|
||||
}
|
||||
|
||||
/*
|
||||
* Postpone the firmware download to a point in time when we
|
||||
* know the correct PLL setup
|
||||
*/
|
||||
if (clkdiv != ADAU1707_CLKDIV_UNSET) {
|
||||
ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
|
||||
if (ret) {
|
||||
dev_warn(codec->dev, "Failed to load firmware\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
|
||||
regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
|
||||
|
||||
regcache_mark_dirty(adau1701->regmap);
|
||||
regcache_sync(adau1701->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
|
||||
unsigned int val;
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val = ADAU1701_SEROCTL_WORD_LEN_16;
|
||||
break;
|
||||
case 20:
|
||||
val = ADAU1701_SEROCTL_WORD_LEN_20;
|
||||
break;
|
||||
case 24:
|
||||
val = ADAU1701_SEROCTL_WORD_LEN_24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) {
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val |= ADAU1701_SEROCTL_MSB_DEALY16;
|
||||
break;
|
||||
case 20:
|
||||
val |= ADAU1701_SEROCTL_MSB_DEALY12;
|
||||
break;
|
||||
case 24:
|
||||
val |= ADAU1701_SEROCTL_MSB_DEALY8;
|
||||
break;
|
||||
}
|
||||
mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
|
||||
return 0;
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val = ADAU1701_SERICTL_RIGHTJ_16;
|
||||
break;
|
||||
case 20:
|
||||
val = ADAU1701_SERICTL_RIGHTJ_20;
|
||||
break;
|
||||
case 24:
|
||||
val = ADAU1701_SERICTL_RIGHTJ_24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_SERICTL,
|
||||
ADAU1701_SERICTL_MODE_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int clkdiv = adau1701->sysclk / params_rate(params);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If the mclk/lrclk ratio changes, the chip needs updated PLL
|
||||
* mode GPIO settings, and a full reset cycle, including a new
|
||||
* firmware upload.
|
||||
*/
|
||||
if (clkdiv != adau1701->pll_clkdiv) {
|
||||
ret = adau1701_reset(codec, clkdiv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 192000:
|
||||
val = ADAU1701_DSPCTRL_SR_192;
|
||||
break;
|
||||
case 96000:
|
||||
val = ADAU1701_DSPCTRL_SR_96;
|
||||
break;
|
||||
case 48000:
|
||||
val = ADAU1701_DSPCTRL_SR_48;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
|
||||
ADAU1701_DSPCTRL_SR_MASK, val);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
return adau1701_set_playback_pcm_format(codec, params);
|
||||
else
|
||||
return adau1701_set_capture_pcm_format(codec, params);
|
||||
}
|
||||
|
||||
static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int serictl = 0x00, seroctl = 0x00;
|
||||
bool invert_lrclk;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* master, 64-bits per sample, 1 frame per sample */
|
||||
seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16
|
||||
| ADAU1701_SEROCTL_OLF1024;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clock inversion */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
invert_lrclk = false;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
invert_lrclk = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
invert_lrclk = false;
|
||||
serictl |= ADAU1701_SERICTL_INV_BCLK;
|
||||
seroctl |= ADAU1701_SEROCTL_INV_BCLK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
invert_lrclk = true;
|
||||
serictl |= ADAU1701_SERICTL_INV_BCLK;
|
||||
seroctl |= ADAU1701_SEROCTL_INV_BCLK;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
serictl |= ADAU1701_SERICTL_LEFTJ;
|
||||
seroctl |= ADAU1701_SEROCTL_MSB_DEALY0;
|
||||
invert_lrclk = !invert_lrclk;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
serictl |= ADAU1701_SERICTL_RIGHTJ_24;
|
||||
seroctl |= ADAU1701_SEROCTL_MSB_DEALY8;
|
||||
invert_lrclk = !invert_lrclk;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (invert_lrclk) {
|
||||
seroctl |= ADAU1701_SEROCTL_INV_LRCLK;
|
||||
serictl |= ADAU1701_SERICTL_INV_LRCLK;
|
||||
}
|
||||
|
||||
adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
|
||||
regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
|
||||
~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
/* Enable VREF and VREF buffer */
|
||||
regmap_update_bits(adau1701->regmap,
|
||||
ADAU1701_AUXNPOW, mask, 0x00);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* Disable VREF and VREF buffer */
|
||||
regmap_update_bits(adau1701->regmap,
|
||||
ADAU1701_AUXNPOW, mask, mask);
|
||||
break;
|
||||
}
|
||||
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
unsigned int mask = ADAU1701_DSPCTRL_DAM;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (mute)
|
||||
val = 0;
|
||||
else
|
||||
val = mask;
|
||||
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
unsigned int val;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU1701_CLK_SRC_OSC:
|
||||
val = 0x0;
|
||||
break;
|
||||
case ADAU1701_CLK_SRC_MCLK:
|
||||
val = ADAU1701_OSCIPOW_OPD;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau1701->regmap, ADAU1701_OSCIPOW,
|
||||
ADAU1701_OSCIPOW_OPD, val);
|
||||
adau1701->sysclk = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops adau1701_dai_ops = {
|
||||
.set_fmt = adau1701_set_dai_fmt,
|
||||
.hw_params = adau1701_hw_params,
|
||||
.digital_mute = adau1701_digital_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau1701_dai = {
|
||||
.name = "adau1701",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = ADAU1701_RATES,
|
||||
.formats = ADAU1701_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = ADAU1701_RATES,
|
||||
.formats = ADAU1701_FORMATS,
|
||||
},
|
||||
.ops = &adau1701_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id adau1701_dt_ids[] = {
|
||||
{ .compatible = "adi,adau1701", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
|
||||
#endif
|
||||
|
||||
static int adau1701_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int i, ret;
|
||||
unsigned int val;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/*
|
||||
* Let the pll_clkdiv variable default to something that won't happen
|
||||
* at runtime. That way, we can postpone the firmware download from
|
||||
* adau1701_reset() to a point in time when we know the correct PLL
|
||||
* mode parameters.
|
||||
*/
|
||||
adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
|
||||
|
||||
/* initalize with pre-configured pll mode settings */
|
||||
ret = adau1701_reset(codec, adau1701->pll_clkdiv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set up pin config */
|
||||
val = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
val |= adau1701->pin_config[i] << (i * 4);
|
||||
|
||||
regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val);
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
val |= adau1701->pin_config[i + 6] << (i * 4);
|
||||
|
||||
regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver adau1701_codec_drv = {
|
||||
.probe = adau1701_probe,
|
||||
.set_bias_level = adau1701_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
|
||||
.controls = adau1701_controls,
|
||||
.num_controls = ARRAY_SIZE(adau1701_controls),
|
||||
.dapm_widgets = adau1701_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets),
|
||||
.dapm_routes = adau1701_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes),
|
||||
|
||||
.set_sysclk = adau1701_set_sysclk,
|
||||
};
|
||||
|
||||
static const struct regmap_config adau1701_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 32,
|
||||
.max_register = ADAU1701_MAX_REGISTER,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_reg = adau1701_volatile_reg,
|
||||
.reg_write = adau1701_reg_write,
|
||||
.reg_read = adau1701_reg_read,
|
||||
};
|
||||
|
||||
static int adau1701_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adau1701 *adau1701;
|
||||
struct device *dev = &client->dev;
|
||||
int gpio_nreset = -EINVAL;
|
||||
int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
|
||||
int ret;
|
||||
|
||||
adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
|
||||
if (!adau1701)
|
||||
return -ENOMEM;
|
||||
|
||||
adau1701->regmap = devm_regmap_init(dev, NULL, client,
|
||||
&adau1701_regmap);
|
||||
if (IS_ERR(adau1701->regmap))
|
||||
return PTR_ERR(adau1701->regmap);
|
||||
|
||||
if (dev->of_node) {
|
||||
gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
|
||||
if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
|
||||
return gpio_nreset;
|
||||
|
||||
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)
|
||||
return gpio_pll_mode[0];
|
||||
|
||||
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)
|
||||
return gpio_pll_mode[1];
|
||||
|
||||
of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
|
||||
&adau1701->pll_clkdiv);
|
||||
|
||||
of_property_read_u8_array(dev->of_node, "adi,pin-config",
|
||||
adau1701->pin_config,
|
||||
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)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"ADAU1701 PLL mode 1");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
|
||||
&adau1701_dai, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adau1701_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1701_i2c_id[] = {
|
||||
{ "adau1401", 0 },
|
||||
{ "adau1401a", 0 },
|
||||
{ "adau1701", 0 },
|
||||
{ "adau1702", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
|
||||
|
||||
static struct i2c_driver adau1701_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1701",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(adau1701_dt_ids),
|
||||
},
|
||||
.probe = adau1701_i2c_probe,
|
||||
.remove = adau1701_i2c_remove,
|
||||
.id_table = adau1701_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adau1701_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
|
||||
MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
17
sound/soc/codecs/adau1701.h
Normal file
17
sound/soc/codecs/adau1701.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* header file for ADAU1701 SigmaDSP processor
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef _ADAU1701_H
|
||||
#define _ADAU1701_H
|
||||
|
||||
enum adau1701_clk_src {
|
||||
ADAU1701_CLK_SRC_OSC,
|
||||
ADAU1701_CLK_SRC_MCLK,
|
||||
};
|
||||
|
||||
#endif
|
||||
60
sound/soc/codecs/adau1761-i2c.c
Normal file
60
sound/soc/codecs/adau1761-i2c.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1761.h"
|
||||
|
||||
static int adau1761_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adau1761_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
|
||||
return adau1761_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config),
|
||||
id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static int adau1761_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1761_i2c_ids[] = {
|
||||
{ "adau1361", ADAU1361 },
|
||||
{ "adau1461", ADAU1761 },
|
||||
{ "adau1761", ADAU1761 },
|
||||
{ "adau1961", ADAU1361 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
|
||||
|
||||
static struct i2c_driver adau1761_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1761",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1761_i2c_probe,
|
||||
.remove = adau1761_i2c_remove,
|
||||
.id_table = adau1761_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(adau1761_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
77
sound/soc/codecs/adau1761-spi.c
Normal file
77
sound/soc/codecs/adau1761-spi.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1761.h"
|
||||
|
||||
static void adau1761_spi_switch_mode(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/*
|
||||
* To get the device into SPI mode CLATCH has to be pulled low three
|
||||
* times. Do this by issuing three dummy reads.
|
||||
*/
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
}
|
||||
|
||||
static int adau1761_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap_config config;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
config = adau1761_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 24;
|
||||
config.read_flag_mask = 0x1;
|
||||
|
||||
return adau1761_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &config),
|
||||
id->driver_data, adau1761_spi_switch_mode);
|
||||
}
|
||||
|
||||
static int adau1761_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id adau1761_spi_id[] = {
|
||||
{ "adau1361", ADAU1361 },
|
||||
{ "adau1461", ADAU1761 },
|
||||
{ "adau1761", ADAU1761 },
|
||||
{ "adau1961", ADAU1361 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
|
||||
|
||||
static struct spi_driver adau1761_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1761",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1761_spi_probe,
|
||||
.remove = adau1761_spi_remove,
|
||||
.id_table = adau1761_spi_id,
|
||||
};
|
||||
module_spi_driver(adau1761_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
807
sound/soc/codecs/adau1761.c
Normal file
807
sound/soc/codecs/adau1761.c
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2011-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
#include "adau17x1.h"
|
||||
#include "adau1761.h"
|
||||
|
||||
#define ADAU1761_DIGMIC_JACKDETECT 0x4008
|
||||
#define ADAU1761_REC_MIXER_LEFT0 0x400a
|
||||
#define ADAU1761_REC_MIXER_LEFT1 0x400b
|
||||
#define ADAU1761_REC_MIXER_RIGHT0 0x400c
|
||||
#define ADAU1761_REC_MIXER_RIGHT1 0x400d
|
||||
#define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e
|
||||
#define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f
|
||||
#define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020
|
||||
#define ADAU1761_PLAY_MIXER_LEFT0 0x401c
|
||||
#define ADAU1761_PLAY_MIXER_LEFT1 0x401d
|
||||
#define ADAU1761_PLAY_MIXER_RIGHT0 0x401e
|
||||
#define ADAU1761_PLAY_MIXER_RIGHT1 0x401f
|
||||
#define ADAU1761_PLAY_LR_MIXER_RIGHT 0x4021
|
||||
#define ADAU1761_PLAY_MIXER_MONO 0x4022
|
||||
#define ADAU1761_PLAY_HP_LEFT_VOL 0x4023
|
||||
#define ADAU1761_PLAY_HP_RIGHT_VOL 0x4024
|
||||
#define ADAU1761_PLAY_LINE_LEFT_VOL 0x4025
|
||||
#define ADAU1761_PLAY_LINE_RIGHT_VOL 0x4026
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL 0x4027
|
||||
#define ADAU1761_POP_CLICK_SUPPRESS 0x4028
|
||||
#define ADAU1761_JACK_DETECT_PIN 0x4031
|
||||
#define ADAU1761_DEJITTER 0x4036
|
||||
#define ADAU1761_CLK_ENABLE0 0x40f9
|
||||
#define ADAU1761_CLK_ENABLE1 0x40fa
|
||||
|
||||
#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW BIT(0)
|
||||
#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC BIT(5)
|
||||
|
||||
#define ADAU1761_DIFF_INPUT_VOL_LDEN BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP BIT(0)
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE BIT(1)
|
||||
|
||||
#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP BIT(0)
|
||||
|
||||
|
||||
#define ADAU1761_FIRMWARE "adau1761.bin"
|
||||
|
||||
static const struct reg_default adau1761_reg_defaults[] = {
|
||||
{ ADAU1761_DEJITTER, 0x03 },
|
||||
{ ADAU1761_DIGMIC_JACKDETECT, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_LEFT0, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_LEFT1, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_RIGHT0, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_RIGHT1, 0x00 },
|
||||
{ ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
|
||||
{ ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_MONO, 0x00 },
|
||||
{ ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_HP_RIGHT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LINE_LEFT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
|
||||
{ ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
|
||||
{ ADAU1761_JACK_DETECT_PIN, 0x00 },
|
||||
{ ADAU1761_CLK_ENABLE0, 0x00 },
|
||||
{ ADAU1761_CLK_ENABLE1, 0x00 },
|
||||
{ ADAU17X1_CLOCK_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLL_CONTROL, 0x00 },
|
||||
{ ADAU17X1_REC_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_MICBIAS, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT0, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT1, 0x00 },
|
||||
{ ADAU17X1_CONVERTER0, 0x00 },
|
||||
{ ADAU17X1_CONVERTER1, 0x00 },
|
||||
{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_ADC_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL0, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL1, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL2, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT_PAD, 0xaa },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
|
||||
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
|
||||
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_DSP_ENABLE, 0x00 },
|
||||
{ ADAU17X1_DSP_RUN, 0x00 },
|
||||
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
|
||||
|
||||
static const unsigned int adau1761_bias_select_values[] = {
|
||||
0, 2, 3,
|
||||
};
|
||||
|
||||
static const char * const adau1761_bias_select_text[] = {
|
||||
"Normal operation", "Enhanced performance", "Power saving",
|
||||
};
|
||||
|
||||
static const char * const adau1761_bias_select_extreme_text[] = {
|
||||
"Normal operation", "Extreme power saving", "Enhanced performance",
|
||||
"Power saving",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text);
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text,
|
||||
adau1761_bias_select_values);
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
|
||||
adau1761_bias_select_values);
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
|
||||
SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
|
||||
4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0,
|
||||
adau1761_diff_in_tlv),
|
||||
SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
|
||||
ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
|
||||
SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
|
||||
4, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
|
||||
1, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
|
||||
4, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
|
||||
1, 7, 0, adau1761_sing_in_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1,
|
||||
ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0),
|
||||
SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0),
|
||||
|
||||
SOC_ENUM("ADC Bias", adau1761_adc_bias_enum),
|
||||
SOC_ENUM("DAC Bias", adau1761_dac_bias_enum),
|
||||
SOC_ENUM("Capture Bias", adau1761_capture_bias_enum),
|
||||
SOC_ENUM("Playback Bias", adau1761_playback_bias_enum),
|
||||
SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_mono_controls[] = {
|
||||
SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
1, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Left Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Left Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv),
|
||||
};
|
||||
|
||||
static const char * const adau1761_input_mux_text[] = {
|
||||
"ADC", "DMIC",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum,
|
||||
ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_input_mux_control =
|
||||
SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum);
|
||||
|
||||
static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
* has to be reinitialized. */
|
||||
regmap_write(adau->regmap, ADAU1761_DEJITTER, 0);
|
||||
if (!adau->master)
|
||||
regmap_write(adau->regmap, ADAU1761_DEJITTER, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0,
|
||||
NULL, 0),
|
||||
|
||||
SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0,
|
||||
0, 0, adau1761_left_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0,
|
||||
0, 0, adau1761_right_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT,
|
||||
0, 0, adau1761_left_lr_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT,
|
||||
0, 0, adau1761_right_lr_mixer_controls),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup),
|
||||
|
||||
SND_SOC_DAPM_INPUT("LAUX"),
|
||||
SND_SOC_DAPM_INPUT("RAUX"),
|
||||
SND_SOC_DAPM_INPUT("LINP"),
|
||||
SND_SOC_DAPM_INPUT("LINN"),
|
||||
SND_SOC_DAPM_INPUT("RINP"),
|
||||
SND_SOC_DAPM_INPUT("RINN"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
SND_SOC_DAPM_OUTPUT("LHP"),
|
||||
SND_SOC_DAPM_OUTPUT("RHP"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO,
|
||||
0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("MONOOUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO,
|
||||
0, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = {
|
||||
{ "Left Input Mixer", NULL, "LINP" },
|
||||
{ "Left Input Mixer", NULL, "LINN" },
|
||||
{ "Left Input Mixer", NULL, "LAUX" },
|
||||
|
||||
{ "Right Input Mixer", NULL, "RINP" },
|
||||
{ "Right Input Mixer", NULL, "RINN" },
|
||||
{ "Right Input Mixer", NULL, "RAUX" },
|
||||
|
||||
{ "Left Playback Mixer", NULL, "Left Playback Enable"},
|
||||
{ "Right Playback Mixer", NULL, "Right Playback Enable"},
|
||||
{ "Left LR Playback Mixer", NULL, "Left Playback Enable"},
|
||||
{ "Right LR Playback Mixer", NULL, "Right Playback Enable"},
|
||||
|
||||
{ "Left Playback Mixer", "Left DAC Switch", "Left DAC" },
|
||||
{ "Left Playback Mixer", "Right DAC Switch", "Right DAC" },
|
||||
|
||||
{ "Right Playback Mixer", "Left DAC Switch", "Left DAC" },
|
||||
{ "Right Playback Mixer", "Right DAC Switch", "Right DAC" },
|
||||
|
||||
{ "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
|
||||
{ "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
|
||||
|
||||
{ "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
|
||||
{ "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
|
||||
|
||||
{ "LHP", NULL, "Left Playback Mixer" },
|
||||
{ "RHP", NULL, "Right Playback Mixer" },
|
||||
|
||||
{ "LHP", NULL, "Headphone" },
|
||||
{ "RHP", NULL, "Headphone" },
|
||||
|
||||
{ "LOUT", NULL, "Left LR Playback Mixer" },
|
||||
{ "ROUT", NULL, "Right LR Playback Mixer" },
|
||||
|
||||
{ "Left Playback Mixer", "Aux Bypass Volume", "LAUX" },
|
||||
{ "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
|
||||
{ "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
|
||||
{ "Right Playback Mixer", "Aux Bypass Volume", "RAUX" },
|
||||
{ "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
|
||||
{ "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = {
|
||||
{ "Mono Playback Mixer", NULL, "Left Playback Mixer" },
|
||||
{ "Mono Playback Mixer", NULL, "Right Playback Mixer" },
|
||||
|
||||
{ "MONOOUT", NULL, "Mono Playback Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = {
|
||||
{ "Headphone", NULL, "Headphone VGND" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau1761_input_mux_control),
|
||||
SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau1761_input_mux_control),
|
||||
|
||||
SND_SOC_DAPM_INPUT("DMIC"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_dmic_routes[] = {
|
||||
{ "Left Decimator Mux", "ADC", "Left Input Mixer" },
|
||||
{ "Left Decimator Mux", "DMIC", "DMIC" },
|
||||
{ "Right Decimator Mux", "ADC", "Right Input Mixer" },
|
||||
{ "Right Decimator Mux", "DMIC", "DMIC" },
|
||||
|
||||
{ "Left Decimator", NULL, "Left Decimator Mux" },
|
||||
{ "Right Decimator", NULL, "Right Decimator Mux" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = {
|
||||
{ "Left Decimator", NULL, "Left Input Mixer" },
|
||||
{ "Right Decimator", NULL, "Right Input Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0,
|
||||
1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0,
|
||||
3, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0,
|
||||
4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0,
|
||||
2, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ALC Clock", ADAU1761_CLK_ENABLE0, 5, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1,
|
||||
1, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
|
||||
{ "Left Decimator", NULL, "Digital Clock 0", },
|
||||
{ "Right Decimator", NULL, "Digital Clock 0", },
|
||||
{ "Left DAC", NULL, "Digital Clock 0", },
|
||||
{ "Right DAC", NULL, "Digital Clock 0", },
|
||||
|
||||
{ "AIFCLK", NULL, "Digital Clock 1" },
|
||||
|
||||
{ "Playback", NULL, "Serial Port Clock" },
|
||||
{ "Capture", NULL, "Serial Port Clock" },
|
||||
{ "Playback", NULL, "Serial Input Routing Clock" },
|
||||
{ "Capture", NULL, "Serial Output Routing Clock" },
|
||||
|
||||
{ "Left Decimator", NULL, "Decimator Resync Clock" },
|
||||
{ "Right Decimator", NULL, "Decimator Resync Clock" },
|
||||
{ "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" },
|
||||
|
||||
{ "Left Input Mixer", NULL, "ALC Clock" },
|
||||
{ "Right Input Mixer", NULL, "ALC Clock" },
|
||||
|
||||
{ "Digital Clock 0", NULL, "SYSCLK" },
|
||||
{ "Digital Clock 1", NULL, "SYSCLK" },
|
||||
};
|
||||
|
||||
static int adau1761_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum adau1761_output_mode adau1761_get_lineout_mode(
|
||||
struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
|
||||
if (pdata)
|
||||
return pdata->lineout_mode;
|
||||
|
||||
return ADAU1761_OUTPUT_MODE_LINE;
|
||||
}
|
||||
|
||||
static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
enum adau1761_digmic_jackdet_pin_mode mode;
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
mode = pdata->digmic_jackdetect_pin_mode;
|
||||
else
|
||||
mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE;
|
||||
|
||||
switch (mode) {
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT:
|
||||
switch (pdata->jackdetect_debounce_time) {
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_5MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_10MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_20MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_40MS:
|
||||
val |= pdata->jackdetect_debounce_time << 6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pdata->jackdetect_active_low)
|
||||
val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_jack_detect_controls,
|
||||
ARRAY_SIZE(adau1761_jack_detect_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_no_dmic_routes,
|
||||
ARRAY_SIZE(adau1761_no_dmic_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_dmic_widgets,
|
||||
ARRAY_SIZE(adau1761_dmic_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_dmic_routes,
|
||||
ARRAY_SIZE(adau1761_dmic_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
enum adau1761_output_mode mode;
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
mode = pdata->headphone_mode;
|
||||
else
|
||||
mode = ADAU1761_OUTPUT_MODE_HEADPHONE;
|
||||
|
||||
switch (mode) {
|
||||
case ADAU1761_OUTPUT_MODE_LINE:
|
||||
break;
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE,
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE);
|
||||
/* fallthrough */
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_capless_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_capless_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_capless_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_capless_dapm_routes));
|
||||
} else {
|
||||
ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls,
|
||||
ARRAY_SIZE(adau1761_mono_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_mono_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_mono_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_mono_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_mono_dapm_routes));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool adau1761_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1761_DIGMIC_JACKDETECT:
|
||||
case ADAU1761_REC_MIXER_LEFT0:
|
||||
case ADAU1761_REC_MIXER_LEFT1:
|
||||
case ADAU1761_REC_MIXER_RIGHT0:
|
||||
case ADAU1761_REC_MIXER_RIGHT1:
|
||||
case ADAU1761_LEFT_DIFF_INPUT_VOL:
|
||||
case ADAU1761_RIGHT_DIFF_INPUT_VOL:
|
||||
case ADAU1761_PLAY_LR_MIXER_LEFT:
|
||||
case ADAU1761_PLAY_MIXER_LEFT0:
|
||||
case ADAU1761_PLAY_MIXER_LEFT1:
|
||||
case ADAU1761_PLAY_MIXER_RIGHT0:
|
||||
case ADAU1761_PLAY_MIXER_RIGHT1:
|
||||
case ADAU1761_PLAY_LR_MIXER_RIGHT:
|
||||
case ADAU1761_PLAY_MIXER_MONO:
|
||||
case ADAU1761_PLAY_HP_LEFT_VOL:
|
||||
case ADAU1761_PLAY_HP_RIGHT_VOL:
|
||||
case ADAU1761_PLAY_LINE_LEFT_VOL:
|
||||
case ADAU1761_PLAY_LINE_RIGHT_VOL:
|
||||
case ADAU1761_PLAY_MONO_OUTPUT_VOL:
|
||||
case ADAU1761_POP_CLICK_SUPPRESS:
|
||||
case ADAU1761_JACK_DETECT_PIN:
|
||||
case ADAU1761_DEJITTER:
|
||||
case ADAU1761_CLK_ENABLE0:
|
||||
case ADAU1761_CLK_ENABLE1:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return adau17x1_readable_register(dev, reg);
|
||||
}
|
||||
|
||||
static int adau1761_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_add_widgets(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (pdata && pdata->input_differential) {
|
||||
regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN);
|
||||
regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN);
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_differential_mode_controls,
|
||||
ARRAY_SIZE(adau1761_differential_mode_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_single_mode_controls,
|
||||
ARRAY_SIZE(adau1761_single_mode_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (adau1761_get_lineout_mode(codec)) {
|
||||
case ADAU1761_OUTPUT_MODE_LINE:
|
||||
break;
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP);
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau1761_setup_headphone_mode(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau1761_setup_digmic_jackdetect(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau->type == ADAU1761) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev,
|
||||
ADAU1761_FIRMWARE);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to firmware\n");
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver adau1761_codec_driver = {
|
||||
.probe = adau1761_codec_probe,
|
||||
.resume = adau17x1_resume,
|
||||
.set_bias_level = adau1761_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = adau1761_controls,
|
||||
.num_controls = ARRAY_SIZE(adau1761_controls),
|
||||
.dapm_widgets = adau1x61_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
|
||||
.dapm_routes = adau1x61_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
|
||||
};
|
||||
|
||||
#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver adau1361_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau1761_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
int adau1761_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == ADAU1361)
|
||||
dai_drv = &adau1361_dai_driver;
|
||||
else
|
||||
dai_drv = &adau1761_dai_driver;
|
||||
|
||||
return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau1761_probe);
|
||||
|
||||
const struct regmap_config adau1761_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.max_register = 0x40fa,
|
||||
.reg_defaults = adau1761_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
|
||||
.readable_reg = adau1761_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1761_regmap_config);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
23
sound/soc/codecs/adau1761.h
Normal file
23
sound/soc/codecs/adau1761.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_CODECS_ADAU1761_H__
|
||||
#define __SOUND_SOC_CODECS_ADAU1761_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include "adau17x1.h"
|
||||
|
||||
struct device;
|
||||
|
||||
int adau1761_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
|
||||
extern const struct regmap_config adau1761_regmap_config;
|
||||
|
||||
#endif
|
||||
58
sound/soc/codecs/adau1781-i2c.c
Normal file
58
sound/soc/codecs/adau1781-i2c.c
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Driver for ADAU1381/ADAU1781 CODEC
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1781.h"
|
||||
|
||||
static int adau1781_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adau1781_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
|
||||
return adau1781_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config),
|
||||
id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static int adau1781_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1781_i2c_ids[] = {
|
||||
{ "adau1381", ADAU1381 },
|
||||
{ "adau1781", ADAU1781 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
|
||||
|
||||
static struct i2c_driver adau1781_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1781",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1781_i2c_probe,
|
||||
.remove = adau1781_i2c_remove,
|
||||
.id_table = adau1781_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(adau1781_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC I2C driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
75
sound/soc/codecs/adau1781-spi.c
Normal file
75
sound/soc/codecs/adau1781-spi.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Driver for ADAU1381/ADAU1781 CODEC
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1781.h"
|
||||
|
||||
static void adau1781_spi_switch_mode(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/*
|
||||
* To get the device into SPI mode CLATCH has to be pulled low three
|
||||
* times. Do this by issuing three dummy reads.
|
||||
*/
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
}
|
||||
|
||||
static int adau1781_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap_config config;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
config = adau1781_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 24;
|
||||
config.read_flag_mask = 0x1;
|
||||
|
||||
return adau1781_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &config),
|
||||
id->driver_data, adau1781_spi_switch_mode);
|
||||
}
|
||||
|
||||
static int adau1781_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id adau1781_spi_id[] = {
|
||||
{ "adau1381", ADAU1381 },
|
||||
{ "adau1781", ADAU1781 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1781_spi_id);
|
||||
|
||||
static struct spi_driver adau1781_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1781",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1781_spi_probe,
|
||||
.remove = adau1781_spi_remove,
|
||||
.id_table = adau1781_spi_id,
|
||||
};
|
||||
module_spi_driver(adau1781_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC SPI driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
511
sound/soc/codecs/adau1781.c
Normal file
511
sound/soc/codecs/adau1781.c
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Driver for ADAU1781/ADAU1781 codec
|
||||
*
|
||||
* Copyright 2011-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
#include "adau17x1.h"
|
||||
#include "adau1781.h"
|
||||
|
||||
#define ADAU1781_DMIC_BEEP_CTRL 0x4008
|
||||
#define ADAU1781_LEFT_PGA 0x400e
|
||||
#define ADAU1781_RIGHT_PGA 0x400f
|
||||
#define ADAU1781_LEFT_PLAYBACK_MIXER 0x401c
|
||||
#define ADAU1781_RIGHT_PLAYBACK_MIXER 0x401e
|
||||
#define ADAU1781_MONO_PLAYBACK_MIXER 0x401f
|
||||
#define ADAU1781_LEFT_LINEOUT 0x4025
|
||||
#define ADAU1781_RIGHT_LINEOUT 0x4026
|
||||
#define ADAU1781_SPEAKER 0x4027
|
||||
#define ADAU1781_BEEP_ZC 0x4028
|
||||
#define ADAU1781_DEJITTER 0x4032
|
||||
#define ADAU1781_DIG_PWDN0 0x4080
|
||||
#define ADAU1781_DIG_PWDN1 0x4081
|
||||
|
||||
#define ADAU1781_INPUT_DIFFERNTIAL BIT(3)
|
||||
|
||||
#define ADAU1381_FIRMWARE "adau1381.bin"
|
||||
#define ADAU1781_FIRMWARE "adau1781.bin"
|
||||
|
||||
static const struct reg_default adau1781_reg_defaults[] = {
|
||||
{ ADAU1781_DMIC_BEEP_CTRL, 0x00 },
|
||||
{ ADAU1781_LEFT_PGA, 0xc7 },
|
||||
{ ADAU1781_RIGHT_PGA, 0xc7 },
|
||||
{ ADAU1781_LEFT_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_RIGHT_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_MONO_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_LEFT_LINEOUT, 0x00 },
|
||||
{ ADAU1781_RIGHT_LINEOUT, 0x00 },
|
||||
{ ADAU1781_SPEAKER, 0x00 },
|
||||
{ ADAU1781_BEEP_ZC, 0x19 },
|
||||
{ ADAU1781_DEJITTER, 0x60 },
|
||||
{ ADAU1781_DIG_PWDN1, 0x0c },
|
||||
{ ADAU1781_DIG_PWDN1, 0x00 },
|
||||
{ ADAU17X1_CLOCK_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLL_CONTROL, 0x00 },
|
||||
{ ADAU17X1_REC_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_MICBIAS, 0x04 },
|
||||
{ ADAU17X1_SERIAL_PORT0, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT1, 0x00 },
|
||||
{ ADAU17X1_CONVERTER0, 0x00 },
|
||||
{ ADAU17X1_CONVERTER1, 0x00 },
|
||||
{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_ADC_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL0, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL1, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL2, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT_PAD, 0x00 },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD0, 0x00 },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
|
||||
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
|
||||
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_DSP_ENABLE, 0x00 },
|
||||
{ ADAU17X1_DSP_RUN, 0x00 },
|
||||
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1781_speaker_tlv, 0, 200, 0);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(adau1781_pga_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
|
||||
4, 4, TLV_DB_SCALE_ITEM(1700, 0, 0),
|
||||
5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(adau1781_beep_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
|
||||
4, 4, TLV_DB_SCALE_ITEM(-2300, 0, 0),
|
||||
5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1781_sidetone_tlv, -1800, 300, 1);
|
||||
|
||||
static const char * const adau1781_speaker_bias_select_text[] = {
|
||||
"Normal operation", "Power saving", "Enhanced performance",
|
||||
};
|
||||
|
||||
static const char * const adau1781_bias_select_text[] = {
|
||||
"Normal operation", "Extreme power saving", "Power saving",
|
||||
"Enhanced performance",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_adc_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 3, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_speaker_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 6, adau1781_speaker_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_dac_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 4, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_playback_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 2, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_capture_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 1, adau1781_bias_select_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_controls[] = {
|
||||
SOC_SINGLE_TLV("Beep Capture Volume", ADAU1781_DMIC_BEEP_CTRL, 0, 7, 0,
|
||||
adau1781_beep_tlv),
|
||||
SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAU1781_LEFT_PGA,
|
||||
ADAU1781_RIGHT_PGA, 5, 7, 0, adau1781_pga_tlv),
|
||||
SOC_DOUBLE_R("PGA Capture Switch", ADAU1781_LEFT_PGA,
|
||||
ADAU1781_RIGHT_PGA, 1, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R("Lineout Playback Switch", ADAU1781_LEFT_LINEOUT,
|
||||
ADAU1781_RIGHT_LINEOUT, 1, 1, 0),
|
||||
SOC_SINGLE("Beep ZC Switch", ADAU1781_BEEP_ZC, 0, 1, 0),
|
||||
|
||||
SOC_SINGLE("Mono Playback Switch", ADAU1781_MONO_PLAYBACK_MIXER,
|
||||
0, 1, 0),
|
||||
SOC_SINGLE_TLV("Mono Playback Volume", ADAU1781_SPEAKER, 6, 3, 0,
|
||||
adau1781_speaker_tlv),
|
||||
|
||||
SOC_ENUM("ADC Bias", adau1781_adc_bias_enum),
|
||||
SOC_ENUM("DAC Bias", adau1781_dac_bias_enum),
|
||||
SOC_ENUM("Capture Bias", adau1781_capture_bias_enum),
|
||||
SOC_ENUM("Playback Bias", adau1781_playback_bias_enum),
|
||||
SOC_ENUM("Speaker Bias", adau1781_speaker_bias_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_beep_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Beep Capture Switch", ADAU1781_DMIC_BEEP_CTRL,
|
||||
3, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_left_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Switch",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_right_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Switch",
|
||||
ADAU1781_RIGHT_PLAYBACK_MIXER, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left Switch",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right Switch",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 2, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
* has to be reinitialized. */
|
||||
regmap_write(adau->regmap, ADAU1781_DEJITTER, 0);
|
||||
if (!adau->master)
|
||||
regmap_write(adau->regmap, ADAU1781_DEJITTER, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1781_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("Left PGA", ADAU1781_LEFT_PGA, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Right PGA", ADAU1781_RIGHT_PGA, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUT_DRV("Speaker", ADAU1781_SPEAKER, 0, 0, NULL, 0),
|
||||
|
||||
SOC_MIXER_NAMED_CTL_ARRAY("Beep Mixer", ADAU17X1_MICBIAS, 4, 0,
|
||||
adau1781_beep_mixer_controls),
|
||||
|
||||
SOC_MIXER_ARRAY("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_left_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_right_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Mono Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_mono_mixer_controls),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Serial Input Routing", ADAU1781_DIG_PWDN0,
|
||||
2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Output Routing", ADAU1781_DIG_PWDN0,
|
||||
3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Clock Domain Transfer", ADAU1781_DIG_PWDN0,
|
||||
5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Ports", ADAU1781_DIG_PWDN0, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC Engine", ADAU1781_DIG_PWDN0, 7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC Engine", ADAU1781_DIG_PWDN1, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Digital Mic", ADAU1781_DIG_PWDN1, 1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Sound Engine", ADAU1781_DIG_PWDN0, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, ADAU1781_DIG_PWDN0, 1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Zero Crossing Detector", ADAU1781_DIG_PWDN1, 2, 0,
|
||||
NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_POST("Dejitter fixup", adau1781_dejitter_fixup),
|
||||
|
||||
SND_SOC_DAPM_INPUT("BEEP"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("SP"),
|
||||
SND_SOC_DAPM_INPUT("LMIC"),
|
||||
SND_SOC_DAPM_INPUT("RMIC"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_dapm_routes[] = {
|
||||
{ "Left Lineout Mixer", NULL, "Left Playback Enable" },
|
||||
{ "Right Lineout Mixer", NULL, "Right Playback Enable" },
|
||||
|
||||
{ "Left Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Left Lineout Mixer", "Switch", "Left DAC" },
|
||||
|
||||
{ "Right Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Right Lineout Mixer", "Switch", "Right DAC" },
|
||||
|
||||
{ "Mono Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Mono Mixer", "Right Switch", "Right DAC" },
|
||||
{ "Mono Mixer", "Left Switch", "Left DAC" },
|
||||
{ "Speaker", NULL, "Mono Mixer" },
|
||||
|
||||
{ "Mono Mixer", NULL, "SYSCLK" },
|
||||
{ "Left Lineout Mixer", NULL, "SYSCLK" },
|
||||
{ "Left Lineout Mixer", NULL, "SYSCLK" },
|
||||
|
||||
{ "Beep Mixer", "Beep Capture Switch", "BEEP" },
|
||||
{ "Beep Mixer", NULL, "Zero Crossing Detector" },
|
||||
|
||||
{ "Left DAC", NULL, "DAC Engine" },
|
||||
{ "Right DAC", NULL, "DAC Engine" },
|
||||
|
||||
{ "Sound Engine", NULL, "SYSCLK" },
|
||||
{ "DSP", NULL, "Sound Engine" },
|
||||
|
||||
{ "Left Decimator", NULL, "ADC Engine" },
|
||||
{ "Right Decimator", NULL, "ADC Engine" },
|
||||
|
||||
{ "AIFCLK", NULL, "SYSCLK" },
|
||||
|
||||
{ "Playback", NULL, "Serial Input Routing" },
|
||||
{ "Playback", NULL, "Serial Ports" },
|
||||
{ "Playback", NULL, "Clock Domain Transfer" },
|
||||
{ "Capture", NULL, "Serial Output Routing" },
|
||||
{ "Capture", NULL, "Serial Ports" },
|
||||
{ "Capture", NULL, "Clock Domain Transfer" },
|
||||
|
||||
{ "AOUTL", NULL, "Left Lineout Mixer" },
|
||||
{ "AOUTR", NULL, "Right Lineout Mixer" },
|
||||
{ "SP", NULL, "Speaker" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_adc_dapm_routes[] = {
|
||||
{ "Left PGA", NULL, "LMIC" },
|
||||
{ "Right PGA", NULL, "RMIC" },
|
||||
|
||||
{ "Left Decimator", NULL, "Left PGA" },
|
||||
{ "Right Decimator", NULL, "Right PGA" },
|
||||
};
|
||||
|
||||
static const char * const adau1781_dmic_select_text[] = {
|
||||
"DMIC1", "DMIC2",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_VIRT_DECL(adau1781_dmic_select_enum,
|
||||
adau1781_dmic_select_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_dmic_mux =
|
||||
SOC_DAPM_ENUM("DMIC Select", adau1781_dmic_select_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1781_dmic_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("DMIC Select", SND_SOC_NOPM, 0, 0, &adau1781_dmic_mux),
|
||||
|
||||
SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1781_DMIC_BEEP_CTRL, 4, 0),
|
||||
SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1781_DMIC_BEEP_CTRL, 5, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = {
|
||||
{ "DMIC1", NULL, "LMIC" },
|
||||
{ "DMIC2", NULL, "RMIC" },
|
||||
|
||||
{ "DMIC1", NULL, "Digital Mic" },
|
||||
{ "DMIC2", NULL, "Digital Mic" },
|
||||
|
||||
{ "DMIC Select", "DMIC1", "DMIC1" },
|
||||
{ "DMIC Select", "DMIC2", "DMIC2" },
|
||||
|
||||
{ "Left Decimator", NULL, "DMIC Select" },
|
||||
{ "Right Decimator", NULL, "DMIC Select" },
|
||||
};
|
||||
|
||||
static int adau1781_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
|
||||
|
||||
/* Precharge */
|
||||
regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0x8, 0x8);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0xc, 0x0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool adau1781_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1781_DMIC_BEEP_CTRL:
|
||||
case ADAU1781_LEFT_PGA:
|
||||
case ADAU1781_RIGHT_PGA:
|
||||
case ADAU1781_LEFT_PLAYBACK_MIXER:
|
||||
case ADAU1781_RIGHT_PLAYBACK_MIXER:
|
||||
case ADAU1781_MONO_PLAYBACK_MIXER:
|
||||
case ADAU1781_LEFT_LINEOUT:
|
||||
case ADAU1781_RIGHT_LINEOUT:
|
||||
case ADAU1781_SPEAKER:
|
||||
case ADAU1781_BEEP_ZC:
|
||||
case ADAU1781_DEJITTER:
|
||||
case ADAU1781_DIG_PWDN0:
|
||||
case ADAU1781_DIG_PWDN1:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return adau17x1_readable_register(dev, reg);
|
||||
}
|
||||
|
||||
static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
|
||||
bool differential)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (differential)
|
||||
val = ADAU1781_INPUT_DIFFERNTIAL;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return regmap_update_bits(adau->regmap, reg,
|
||||
ADAU1781_INPUT_DIFFERNTIAL, val);
|
||||
}
|
||||
|
||||
static int adau1781_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
const char *firmware;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_add_widgets(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pdata) {
|
||||
ret = adau1781_set_input_mode(adau, ADAU1781_LEFT_PGA,
|
||||
pdata->left_input_differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = adau1781_set_input_mode(adau, ADAU1781_RIGHT_PGA,
|
||||
pdata->right_input_differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata && pdata->use_dmic) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1781_dmic_dapm_widgets,
|
||||
ARRAY_SIZE(adau1781_dmic_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1781_dmic_dapm_routes,
|
||||
ARRAY_SIZE(adau1781_dmic_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1781_adc_dapm_routes,
|
||||
ARRAY_SIZE(adau1781_adc_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (adau->type) {
|
||||
case ADAU1381:
|
||||
firmware = ADAU1381_FIRMWARE;
|
||||
break;
|
||||
case ADAU1781:
|
||||
firmware = ADAU1781_FIRMWARE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev, firmware);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to load firmware\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver adau1781_codec_driver = {
|
||||
.probe = adau1781_codec_probe,
|
||||
.resume = adau17x1_resume,
|
||||
.set_bias_level = adau1781_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = adau1781_controls,
|
||||
.num_controls = ARRAY_SIZE(adau1781_controls),
|
||||
.dapm_widgets = adau1781_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets),
|
||||
.dapm_routes = adau1781_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes),
|
||||
};
|
||||
|
||||
#define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver adau1781_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1781_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1781_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
const struct regmap_config adau1781_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.max_register = 0x40f8,
|
||||
.reg_defaults = adau1781_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults),
|
||||
.readable_reg = adau1781_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1781_regmap_config);
|
||||
|
||||
int adau1781_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snd_soc_register_codec(dev, &adau1781_codec_driver,
|
||||
&adau1781_dai_driver, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau1781_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
23
sound/soc/codecs/adau1781.h
Normal file
23
sound/soc/codecs/adau1781.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ADAU1381/ADAU1781 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_CODECS_ADAU1781_H__
|
||||
#define __SOUND_SOC_CODECS_ADAU1781_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include "adau17x1.h"
|
||||
|
||||
struct device;
|
||||
|
||||
int adau1781_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
|
||||
extern const struct regmap_config adau1781_regmap_config;
|
||||
|
||||
#endif
|
||||
858
sound/soc/codecs/adau17x1.c
Normal file
858
sound/soc/codecs/adau17x1.c
Normal file
|
|
@ -0,0 +1,858 @@
|
|||
/*
|
||||
* Common code for ADAU1X61 and ADAU1X81 codecs
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau17x1.h"
|
||||
|
||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text);
|
||||
|
||||
static const char * const adau17x1_mic_bias_mode_text[] = {
|
||||
"Normal operation", "High performance",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum,
|
||||
ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text);
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0);
|
||||
|
||||
static const struct snd_kcontrol_new adau17x1_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Digital Capture Volume",
|
||||
ADAU17X1_LEFT_INPUT_DIGITAL_VOL,
|
||||
ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,
|
||||
0, 0xff, 1, adau17x1_digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1,
|
||||
ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv),
|
||||
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL,
|
||||
5, 1, 0),
|
||||
SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0,
|
||||
2, 1, 0),
|
||||
|
||||
SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum),
|
||||
|
||||
SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
|
||||
};
|
||||
|
||||
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
int ret;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
adau->pll_regs[5] = 1;
|
||||
} else {
|
||||
adau->pll_regs[5] = 0;
|
||||
/* Bypass the PLL when disabled, otherwise registers will become
|
||||
* inaccessible. */
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0);
|
||||
}
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
mdelay(5);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const adau17x1_mono_stereo_text[] = {
|
||||
"Stereo",
|
||||
"Mono Left Channel (L+R)",
|
||||
"Mono Right Channel (L+R)",
|
||||
"Mono (L+R)",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum,
|
||||
ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau17x1_dac_mode_mux =
|
||||
SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
|
||||
1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mode_mux),
|
||||
SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mode_mux),
|
||||
|
||||
SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0),
|
||||
SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0),
|
||||
SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0),
|
||||
SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = {
|
||||
{ "Left Decimator", NULL, "SYSCLK" },
|
||||
{ "Right Decimator", NULL, "SYSCLK" },
|
||||
{ "Left DAC", NULL, "SYSCLK" },
|
||||
{ "Right DAC", NULL, "SYSCLK" },
|
||||
{ "Capture", NULL, "SYSCLK" },
|
||||
{ "Playback", NULL, "SYSCLK" },
|
||||
|
||||
{ "Left DAC", NULL, "Left DAC Mode Mux" },
|
||||
{ "Right DAC", NULL, "Right DAC Mode Mux" },
|
||||
|
||||
{ "Capture", NULL, "AIFCLK" },
|
||||
{ "Playback", NULL, "AIFCLK" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
|
||||
"SYSCLK", NULL, "PLL",
|
||||
};
|
||||
|
||||
/*
|
||||
* The MUX register for the Capture and Playback MUXs selects either DSP as
|
||||
* source/destination or one of the TDM slots. The TDM slot is selected via
|
||||
* snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or
|
||||
* directly to the DAI interface with this control.
|
||||
*/
|
||||
static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct snd_soc_dapm_update update;
|
||||
unsigned int stream = e->shift_l;
|
||||
unsigned int val, change;
|
||||
int reg;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ucontrol->value.enumerated.item[0]) {
|
||||
case 0:
|
||||
val = 0;
|
||||
adau->dsp_bypass[stream] = false;
|
||||
break;
|
||||
default:
|
||||
val = (adau->tdm_slot[stream] * 2) + 1;
|
||||
adau->dsp_bypass[stream] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = ADAU17X1_SERIAL_INPUT_ROUTE;
|
||||
else
|
||||
reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
|
||||
|
||||
change = snd_soc_test_bits(codec, reg, 0xff, val);
|
||||
if (change) {
|
||||
update.kcontrol = kcontrol;
|
||||
update.mask = 0xff;
|
||||
update.reg = reg;
|
||||
update.val = val;
|
||||
|
||||
snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
|
||||
ucontrol->value.enumerated.item[0], e, &update);
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
unsigned int stream = e->shift_l;
|
||||
unsigned int reg, val;
|
||||
int ret;
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = ADAU17X1_SERIAL_INPUT_ROUTE;
|
||||
else
|
||||
reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
|
||||
|
||||
ret = regmap_read(adau->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val != 0)
|
||||
val = 1;
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
|
||||
const struct snd_kcontrol_new _name = \
|
||||
SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
|
||||
ARRAY_SIZE(_text), _text), \
|
||||
adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
|
||||
|
||||
static const char * const adau17x1_dac_mux_text[] = {
|
||||
"DSP",
|
||||
"AIFIN",
|
||||
};
|
||||
|
||||
static const char * const adau17x1_capture_mux_text[] = {
|
||||
"DSP",
|
||||
"Decimator",
|
||||
};
|
||||
|
||||
static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux",
|
||||
SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text);
|
||||
|
||||
static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux",
|
||||
SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SIGGEN("DSP Siggen"),
|
||||
|
||||
SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mux),
|
||||
SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_capture_mux),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
|
||||
{ "DAC Playback Mux", "DSP", "DSP" },
|
||||
{ "DAC Playback Mux", "AIFIN", "Playback" },
|
||||
|
||||
{ "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" },
|
||||
{ "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
|
||||
{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" },
|
||||
|
||||
{ "Capture Mux", "DSP", "DSP" },
|
||||
{ "Capture Mux", "Decimator", "Left Decimator" },
|
||||
{ "Capture Mux", "Decimator", "Right Decimator" },
|
||||
|
||||
{ "Capture", NULL, "Capture Mux" },
|
||||
|
||||
{ "DSP", NULL, "DSP Siggen" },
|
||||
|
||||
{ "DSP", NULL, "Left Decimator" },
|
||||
{ "DSP", NULL, "Right Decimator" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
|
||||
{ "Left DAC Mode Mux", "Stereo", "Playback" },
|
||||
{ "Left DAC Mode Mux", "Mono (L+R)", "Playback" },
|
||||
{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Stereo", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Mono (L+R)", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" },
|
||||
{ "Capture", NULL, "Left Decimator" },
|
||||
{ "Capture", NULL, "Right Decimator" },
|
||||
};
|
||||
|
||||
bool adau17x1_has_dsp(struct adau *adau)
|
||||
{
|
||||
switch (adau->type) {
|
||||
case ADAU1761:
|
||||
case ADAU1381:
|
||||
case ADAU1781:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
|
||||
|
||||
static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val, div, dsp_div;
|
||||
unsigned int freq;
|
||||
|
||||
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
|
||||
freq = adau->pll_freq;
|
||||
else
|
||||
freq = adau->sysclk;
|
||||
|
||||
if (freq % params_rate(params) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (freq / params_rate(params)) {
|
||||
case 1024: /* fs */
|
||||
div = 0;
|
||||
dsp_div = 1;
|
||||
break;
|
||||
case 6144: /* fs / 6 */
|
||||
div = 1;
|
||||
dsp_div = 6;
|
||||
break;
|
||||
case 4096: /* fs / 4 */
|
||||
div = 2;
|
||||
dsp_div = 5;
|
||||
break;
|
||||
case 3072: /* fs / 3 */
|
||||
div = 3;
|
||||
dsp_div = 4;
|
||||
break;
|
||||
case 2048: /* fs / 2 */
|
||||
div = 4;
|
||||
dsp_div = 3;
|
||||
break;
|
||||
case 1536: /* fs / 1.5 */
|
||||
div = 5;
|
||||
dsp_div = 2;
|
||||
break;
|
||||
case 512: /* fs / 0.5 */
|
||||
div = 6;
|
||||
dsp_div = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
|
||||
ADAU17X1_CONVERTER0_CONVSR_MASK, div);
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
|
||||
}
|
||||
|
||||
if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
|
||||
return 0;
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY16;
|
||||
break;
|
||||
case 24:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY8;
|
||||
break;
|
||||
case 32:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
|
||||
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->pll_regs[0] = m >> 8;
|
||||
adau->pll_regs[1] = m & 0xff;
|
||||
adau->pll_regs[2] = n >> 8;
|
||||
adau->pll_regs[3] = n & 0xff;
|
||||
adau->pll_regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
adau->pll_regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (adau->clk_src != clk_id) {
|
||||
if (clk_id == ADAU17X1_CLK_SRC_PLL) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
unsigned int ctrl0, ctrl1;
|
||||
int lrclk_pol;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER;
|
||||
adau->master = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
ctrl0 = 0;
|
||||
adau->master = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
lrclk_pol = 0;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
lrclk_pol = 1;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
lrclk_pol = 1;
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
lrclk_pol = 1;
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
lrclk_pol = !lrclk_pol;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
|
||||
lrclk_pol = !lrclk_pol;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lrclk_pol)
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL;
|
||||
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0);
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1);
|
||||
|
||||
adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
unsigned int ser_ctrl0, ser_ctrl1;
|
||||
unsigned int conv_ctrl0, conv_ctrl1;
|
||||
|
||||
/* I2S mode */
|
||||
if (slots == 0) {
|
||||
slots = 2;
|
||||
rx_mask = 3;
|
||||
tx_mask = 3;
|
||||
slot_width = 32;
|
||||
}
|
||||
|
||||
switch (slots) {
|
||||
case 2:
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4;
|
||||
break;
|
||||
case 8:
|
||||
if (adau->type == ADAU1361)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (slot_width * slots) {
|
||||
case 32:
|
||||
if (adau->type == ADAU1761)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
|
||||
break;
|
||||
case 64:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64;
|
||||
break;
|
||||
case 48:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48;
|
||||
break;
|
||||
case 128:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128;
|
||||
break;
|
||||
case 256:
|
||||
if (adau->type == ADAU1361)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (rx_mask) {
|
||||
case 0x03:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1;
|
||||
break;
|
||||
case 0x30:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2;
|
||||
break;
|
||||
case 0xc0:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (tx_mask) {
|
||||
case 0x03:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1;
|
||||
break;
|
||||
case 0x30:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2;
|
||||
break;
|
||||
case 0xc0:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
|
||||
ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1,
|
||||
ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0,
|
||||
ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
|
||||
ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
|
||||
|
||||
if (!adau17x1_has_dsp(adau))
|
||||
return 0;
|
||||
|
||||
if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE,
|
||||
(adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1);
|
||||
}
|
||||
|
||||
if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE,
|
||||
(adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops adau17x1_dai_ops = {
|
||||
.hw_params = adau17x1_hw_params,
|
||||
.set_sysclk = adau17x1_set_dai_sysclk,
|
||||
.set_fmt = adau17x1_set_dai_fmt,
|
||||
.set_pll = adau17x1_set_dai_pll,
|
||||
.set_tdm_slot = adau17x1_set_dai_tdm_slot,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
|
||||
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (micbias) {
|
||||
case ADAU17X1_MICBIAS_0_90_AVDD:
|
||||
case ADAU17X1_MICBIAS_0_65_AVDD:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
|
||||
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU17X1_CLOCK_CONTROL:
|
||||
case ADAU17X1_PLL_CONTROL:
|
||||
case ADAU17X1_REC_POWER_MGMT:
|
||||
case ADAU17X1_MICBIAS:
|
||||
case ADAU17X1_SERIAL_PORT0:
|
||||
case ADAU17X1_SERIAL_PORT1:
|
||||
case ADAU17X1_CONVERTER0:
|
||||
case ADAU17X1_CONVERTER1:
|
||||
case ADAU17X1_LEFT_INPUT_DIGITAL_VOL:
|
||||
case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL:
|
||||
case ADAU17X1_ADC_CONTROL:
|
||||
case ADAU17X1_PLAY_POWER_MGMT:
|
||||
case ADAU17X1_DAC_CONTROL0:
|
||||
case ADAU17X1_DAC_CONTROL1:
|
||||
case ADAU17X1_DAC_CONTROL2:
|
||||
case ADAU17X1_SERIAL_PORT_PAD:
|
||||
case ADAU17X1_CONTROL_PORT_PAD0:
|
||||
case ADAU17X1_CONTROL_PORT_PAD1:
|
||||
case ADAU17X1_DSP_SAMPLING_RATE:
|
||||
case ADAU17X1_SERIAL_INPUT_ROUTE:
|
||||
case ADAU17X1_SERIAL_OUTPUT_ROUTE:
|
||||
case ADAU17X1_DSP_ENABLE:
|
||||
case ADAU17X1_DSP_RUN:
|
||||
case ADAU17X1_SERIAL_SAMPLING_RATE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_readable_register);
|
||||
|
||||
bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* SigmaDSP parameter and program memory */
|
||||
if (reg < 0x4000)
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
/* The PLL register is 6 bytes long */
|
||||
case ADAU17X1_PLL_CONTROL:
|
||||
case ADAU17X1_PLL_CONTROL + 1:
|
||||
case ADAU17X1_PLL_CONTROL + 2:
|
||||
case ADAU17X1_PLL_CONTROL + 3:
|
||||
case ADAU17X1_PLL_CONTROL + 4:
|
||||
case ADAU17X1_PLL_CONTROL + 5:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware)
|
||||
{
|
||||
int ret;
|
||||
int dspsr;
|
||||
|
||||
ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
|
||||
|
||||
ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
|
||||
if (ret) {
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
|
||||
return ret;
|
||||
}
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, adau17x1_controls,
|
||||
ARRAY_SIZE(adau17x1_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
|
||||
ARRAY_SIZE(adau17x1_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau17x1_dsp_dapm_widgets,
|
||||
ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
|
||||
|
||||
int adau17x1_add_routes(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau17x1_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_dsp_dapm_routes));
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau17x1_no_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
||||
|
||||
int adau17x1_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (adau->switch_mode)
|
||||
adau->switch_mode(codec->dev);
|
||||
|
||||
regcache_sync(adau->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_resume);
|
||||
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
struct adau *adau;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL);
|
||||
if (!adau)
|
||||
return -ENOMEM;
|
||||
|
||||
adau->regmap = regmap;
|
||||
adau->switch_mode = switch_mode;
|
||||
adau->type = type;
|
||||
|
||||
dev_set_drvdata(dev, adau);
|
||||
|
||||
if (switch_mode)
|
||||
switch_mode(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
123
sound/soc/codecs/adau17x1.h
Normal file
123
sound/soc/codecs/adau17x1.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#ifndef __ADAU17X1_H__
|
||||
#define __ADAU17X1_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
enum adau17x1_type {
|
||||
ADAU1361,
|
||||
ADAU1761,
|
||||
ADAU1381,
|
||||
ADAU1781,
|
||||
};
|
||||
|
||||
enum adau17x1_pll {
|
||||
ADAU17X1_PLL,
|
||||
};
|
||||
|
||||
enum adau17x1_pll_src {
|
||||
ADAU17X1_PLL_SRC_MCLK,
|
||||
};
|
||||
|
||||
enum adau17x1_clk_src {
|
||||
ADAU17X1_CLK_SRC_MCLK,
|
||||
ADAU17X1_CLK_SRC_PLL,
|
||||
};
|
||||
|
||||
struct adau {
|
||||
unsigned int sysclk;
|
||||
unsigned int pll_freq;
|
||||
|
||||
enum adau17x1_clk_src clk_src;
|
||||
enum adau17x1_type type;
|
||||
void (*switch_mode)(struct device *dev);
|
||||
|
||||
unsigned int dai_fmt;
|
||||
|
||||
uint8_t pll_regs[6];
|
||||
|
||||
bool master;
|
||||
|
||||
unsigned int tdm_slot[2];
|
||||
bool dsp_bypass[2];
|
||||
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec);
|
||||
int adau17x1_add_routes(struct snd_soc_codec *codec);
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias);
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
||||
bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
|
||||
int adau17x1_resume(struct snd_soc_codec *codec);
|
||||
|
||||
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware);
|
||||
bool adau17x1_has_dsp(struct adau *adau);
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL 0x4000
|
||||
#define ADAU17X1_PLL_CONTROL 0x4002
|
||||
#define ADAU17X1_REC_POWER_MGMT 0x4009
|
||||
#define ADAU17X1_MICBIAS 0x4010
|
||||
#define ADAU17X1_SERIAL_PORT0 0x4015
|
||||
#define ADAU17X1_SERIAL_PORT1 0x4016
|
||||
#define ADAU17X1_CONVERTER0 0x4017
|
||||
#define ADAU17X1_CONVERTER1 0x4018
|
||||
#define ADAU17X1_LEFT_INPUT_DIGITAL_VOL 0x401a
|
||||
#define ADAU17X1_RIGHT_INPUT_DIGITAL_VOL 0x401b
|
||||
#define ADAU17X1_ADC_CONTROL 0x4019
|
||||
#define ADAU17X1_PLAY_POWER_MGMT 0x4029
|
||||
#define ADAU17X1_DAC_CONTROL0 0x402a
|
||||
#define ADAU17X1_DAC_CONTROL1 0x402b
|
||||
#define ADAU17X1_DAC_CONTROL2 0x402c
|
||||
#define ADAU17X1_SERIAL_PORT_PAD 0x402d
|
||||
#define ADAU17X1_CONTROL_PORT_PAD0 0x402f
|
||||
#define ADAU17X1_CONTROL_PORT_PAD1 0x4030
|
||||
#define ADAU17X1_DSP_SAMPLING_RATE 0x40eb
|
||||
#define ADAU17X1_SERIAL_INPUT_ROUTE 0x40f2
|
||||
#define ADAU17X1_SERIAL_OUTPUT_ROUTE 0x40f3
|
||||
#define ADAU17X1_DSP_ENABLE 0x40f5
|
||||
#define ADAU17X1_DSP_RUN 0x40f6
|
||||
#define ADAU17X1_SERIAL_SAMPLING_RATE 0x40f8
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT0_BCLK_POL BIT(4)
|
||||
#define ADAU17X1_SERIAL_PORT0_LRCLK_POL BIT(3)
|
||||
#define ADAU17X1_SERIAL_PORT0_MASTER BIT(0)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY1 0x00
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY0 0x01
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY8 0x02
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY16 0x03
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY_MASK 0x03
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL_INFREQ_MASK 0x6
|
||||
#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL BIT(3)
|
||||
#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN BIT(0)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK32 (0x0 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK48 (0x1 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK64 (0x2 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK128 (0x3 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK256 (0x4 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK_MASK (0x7 << 5)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT0_STEREO (0x0 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM4 (0x1 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM8 (0x2 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM_MASK (0x3 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_PULSE_MODE BIT(5)
|
||||
|
||||
#define ADAU17X1_CONVERTER0_DAC_PAIR(x) (((x) - 1) << 5)
|
||||
#define ADAU17X1_CONVERTER0_DAC_PAIR_MASK (0x3 << 5)
|
||||
#define ADAU17X1_CONVERTER1_ADC_PAIR(x) ((x) - 1)
|
||||
#define ADAU17X1_CONVERTER1_ADC_PAIR_MASK 0x3
|
||||
|
||||
#define ADAU17X1_CONVERTER0_CONVSR_MASK 0x7
|
||||
|
||||
|
||||
#endif
|
||||
59
sound/soc/codecs/adau1977-i2c.c
Normal file
59
sound/soc/codecs/adau1977-i2c.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ADAU1977/ADAU1978/ADAU1979 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1977.h"
|
||||
|
||||
static int adau1977_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adau1977_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 8;
|
||||
|
||||
return adau1977_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config),
|
||||
id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static int adau1977_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1977_i2c_ids[] = {
|
||||
{ "adau1977", ADAU1977 },
|
||||
{ "adau1978", ADAU1978 },
|
||||
{ "adau1979", ADAU1978 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
|
||||
|
||||
static struct i2c_driver adau1977_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1977",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1977_i2c_probe,
|
||||
.remove = adau1977_i2c_remove,
|
||||
.id_table = adau1977_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(adau1977_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
76
sound/soc/codecs/adau1977-spi.c
Normal file
76
sound/soc/codecs/adau1977-spi.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* ADAU1977/ADAU1978/ADAU1979 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1977.h"
|
||||
|
||||
static void adau1977_spi_switch_mode(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/*
|
||||
* To get the device into SPI mode CLATCH has to be pulled low three
|
||||
* times. Do this by issuing three dummy reads.
|
||||
*/
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
}
|
||||
|
||||
static int adau1977_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap_config config;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
config = adau1977_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
config.read_flag_mask = 0x1;
|
||||
|
||||
return adau1977_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &config),
|
||||
id->driver_data, adau1977_spi_switch_mode);
|
||||
}
|
||||
|
||||
static int adau1977_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id adau1977_spi_ids[] = {
|
||||
{ "adau1977", ADAU1977 },
|
||||
{ "adau1978", ADAU1978 },
|
||||
{ "adau1979", ADAU1978 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
|
||||
|
||||
static struct spi_driver adau1977_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1977",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1977_spi_probe,
|
||||
.remove = adau1977_spi_remove,
|
||||
.id_table = adau1977_spi_ids,
|
||||
};
|
||||
module_spi_driver(adau1977_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
1018
sound/soc/codecs/adau1977.c
Normal file
1018
sound/soc/codecs/adau1977.c
Normal file
File diff suppressed because it is too large
Load diff
37
sound/soc/codecs/adau1977.h
Normal file
37
sound/soc/codecs/adau1977.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* ADAU1977/ADAU1978/ADAU1979 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_CODECS_ADAU1977_H__
|
||||
#define __SOUND_SOC_CODECS_ADAU1977_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device;
|
||||
|
||||
enum adau1977_type {
|
||||
ADAU1977,
|
||||
ADAU1978,
|
||||
ADAU1979,
|
||||
};
|
||||
|
||||
int adau1977_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau1977_type type, void (*switch_mode)(struct device *dev));
|
||||
|
||||
extern const struct regmap_config adau1977_regmap_config;
|
||||
|
||||
enum adau1977_clk_id {
|
||||
ADAU1977_SYSCLK,
|
||||
};
|
||||
|
||||
enum adau1977_sysclk_src {
|
||||
ADAU1977_SYSCLK_SRC_MCLK,
|
||||
ADAU1977_SYSCLK_SRC_LRCLK,
|
||||
};
|
||||
|
||||
#endif
|
||||
53
sound/soc/codecs/adav801.c
Normal file
53
sound/soc/codecs/adav801.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* ADAV801 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adav80x.h"
|
||||
|
||||
static const struct spi_device_id adav80x_spi_id[] = {
|
||||
{ "adav801", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
|
||||
|
||||
static int adav80x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adav80x_regmap_config;
|
||||
config.read_flag_mask = 0x01;
|
||||
|
||||
return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
|
||||
}
|
||||
|
||||
static int adav80x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver adav80x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adav801",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adav80x_spi_probe,
|
||||
.remove = adav80x_spi_remove,
|
||||
.id_table = adav80x_spi_id,
|
||||
};
|
||||
module_spi_driver(adav80x_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAV801 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
|
||||
MODULE_LICENSE("GPL");
|
||||
50
sound/soc/codecs/adav803.c
Normal file
50
sound/soc/codecs/adav803.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* ADAV803 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adav80x.h"
|
||||
|
||||
static const struct i2c_device_id adav803_id[] = {
|
||||
{ "adav803", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adav803_id);
|
||||
|
||||
static int adav803_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return adav80x_bus_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &adav80x_regmap_config));
|
||||
}
|
||||
|
||||
static int adav803_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver adav803_driver = {
|
||||
.driver = {
|
||||
.name = "adav803",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adav803_probe,
|
||||
.remove = adav803_remove,
|
||||
.id_table = adav803_id,
|
||||
};
|
||||
module_i2c_driver(adav803_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAV803 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
|
||||
MODULE_LICENSE("GPL");
|
||||
880
sound/soc/codecs/adav80x.c
Normal file
880
sound/soc/codecs/adav80x.c
Normal file
|
|
@ -0,0 +1,880 @@
|
|||
/*
|
||||
* ADAV80X Audio Codec driver supporting ADAV801, ADAV803
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Yi Li <yi.li@analog.com>
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "adav80x.h"
|
||||
|
||||
#define ADAV80X_PLAYBACK_CTRL 0x04
|
||||
#define ADAV80X_AUX_IN_CTRL 0x05
|
||||
#define ADAV80X_REC_CTRL 0x06
|
||||
#define ADAV80X_AUX_OUT_CTRL 0x07
|
||||
#define ADAV80X_DPATH_CTRL1 0x62
|
||||
#define ADAV80X_DPATH_CTRL2 0x63
|
||||
#define ADAV80X_DAC_CTRL1 0x64
|
||||
#define ADAV80X_DAC_CTRL2 0x65
|
||||
#define ADAV80X_DAC_CTRL3 0x66
|
||||
#define ADAV80X_DAC_L_VOL 0x68
|
||||
#define ADAV80X_DAC_R_VOL 0x69
|
||||
#define ADAV80X_PGA_L_VOL 0x6c
|
||||
#define ADAV80X_PGA_R_VOL 0x6d
|
||||
#define ADAV80X_ADC_CTRL1 0x6e
|
||||
#define ADAV80X_ADC_CTRL2 0x6f
|
||||
#define ADAV80X_ADC_L_VOL 0x70
|
||||
#define ADAV80X_ADC_R_VOL 0x71
|
||||
#define ADAV80X_PLL_CTRL1 0x74
|
||||
#define ADAV80X_PLL_CTRL2 0x75
|
||||
#define ADAV80X_ICLK_CTRL1 0x76
|
||||
#define ADAV80X_ICLK_CTRL2 0x77
|
||||
#define ADAV80X_PLL_CLK_SRC 0x78
|
||||
#define ADAV80X_PLL_OUTE 0x7a
|
||||
|
||||
#define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00
|
||||
#define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll))
|
||||
#define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll))
|
||||
|
||||
#define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5)
|
||||
#define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2)
|
||||
#define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src)
|
||||
#define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3)
|
||||
|
||||
#define ADAV80X_PLL_CTRL1_PLLDIV 0x10
|
||||
#define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll))
|
||||
#define ADAV80X_PLL_CTRL1_XTLPD 0x02
|
||||
|
||||
#define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4))
|
||||
|
||||
#define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00)
|
||||
#define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08)
|
||||
#define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c)
|
||||
|
||||
#define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02)
|
||||
#define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01)
|
||||
#define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f)
|
||||
|
||||
#define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80
|
||||
#define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00
|
||||
#define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80
|
||||
|
||||
#define ADAV80X_DAC_CTRL1_PD 0x80
|
||||
|
||||
#define ADAV80X_DAC_CTRL2_DIV1 0x00
|
||||
#define ADAV80X_DAC_CTRL2_DIV1_5 0x10
|
||||
#define ADAV80X_DAC_CTRL2_DIV2 0x20
|
||||
#define ADAV80X_DAC_CTRL2_DIV3 0x30
|
||||
#define ADAV80X_DAC_CTRL2_DIV_MASK 0x30
|
||||
|
||||
#define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00
|
||||
#define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40
|
||||
#define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80
|
||||
#define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0
|
||||
|
||||
#define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00
|
||||
#define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01
|
||||
#define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02
|
||||
#define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03
|
||||
#define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01
|
||||
|
||||
#define ADAV80X_CAPTURE_MODE_MASTER 0x20
|
||||
#define ADAV80X_CAPTURE_WORD_LEN24 0x00
|
||||
#define ADAV80X_CAPTURE_WORD_LEN20 0x04
|
||||
#define ADAV80X_CAPTRUE_WORD_LEN18 0x08
|
||||
#define ADAV80X_CAPTURE_WORD_LEN16 0x0c
|
||||
#define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c
|
||||
|
||||
#define ADAV80X_CAPTURE_MODE_LEFT_J 0x00
|
||||
#define ADAV80X_CAPTURE_MODE_I2S 0x01
|
||||
#define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03
|
||||
#define ADAV80X_CAPTURE_MODE_MASK 0x03
|
||||
|
||||
#define ADAV80X_PLAYBACK_MODE_MASTER 0x10
|
||||
#define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00
|
||||
#define ADAV80X_PLAYBACK_MODE_I2S 0x01
|
||||
#define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04
|
||||
#define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05
|
||||
#define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06
|
||||
#define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07
|
||||
#define ADAV80X_PLAYBACK_MODE_MASK 0x07
|
||||
|
||||
#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x))
|
||||
|
||||
static struct reg_default adav80x_reg_defaults[] = {
|
||||
{ ADAV80X_PLAYBACK_CTRL, 0x01 },
|
||||
{ ADAV80X_AUX_IN_CTRL, 0x01 },
|
||||
{ ADAV80X_REC_CTRL, 0x02 },
|
||||
{ ADAV80X_AUX_OUT_CTRL, 0x01 },
|
||||
{ ADAV80X_DPATH_CTRL1, 0xc0 },
|
||||
{ ADAV80X_DPATH_CTRL2, 0x11 },
|
||||
{ ADAV80X_DAC_CTRL1, 0x00 },
|
||||
{ ADAV80X_DAC_CTRL2, 0x00 },
|
||||
{ ADAV80X_DAC_CTRL3, 0x00 },
|
||||
{ ADAV80X_DAC_L_VOL, 0xff },
|
||||
{ ADAV80X_DAC_R_VOL, 0xff },
|
||||
{ ADAV80X_PGA_L_VOL, 0x00 },
|
||||
{ ADAV80X_PGA_R_VOL, 0x00 },
|
||||
{ ADAV80X_ADC_CTRL1, 0x00 },
|
||||
{ ADAV80X_ADC_CTRL2, 0x00 },
|
||||
{ ADAV80X_ADC_L_VOL, 0xff },
|
||||
{ ADAV80X_ADC_R_VOL, 0xff },
|
||||
{ ADAV80X_PLL_CTRL1, 0x00 },
|
||||
{ ADAV80X_PLL_CTRL2, 0x00 },
|
||||
{ ADAV80X_ICLK_CTRL1, 0x00 },
|
||||
{ ADAV80X_ICLK_CTRL2, 0x00 },
|
||||
{ ADAV80X_PLL_CLK_SRC, 0x00 },
|
||||
{ ADAV80X_PLL_OUTE, 0x00 },
|
||||
};
|
||||
|
||||
struct adav80x {
|
||||
struct regmap *regmap;
|
||||
|
||||
enum adav80x_clk_src clk_src;
|
||||
unsigned int sysclk;
|
||||
enum adav80x_pll_src pll_src;
|
||||
|
||||
unsigned int dai_fmt[2];
|
||||
unsigned int rate;
|
||||
bool deemph;
|
||||
bool sysclk_pd[3];
|
||||
};
|
||||
|
||||
static const char *adav80x_mux_text[] = {
|
||||
"ADC",
|
||||
"Playback",
|
||||
"Aux Playback",
|
||||
};
|
||||
|
||||
static const unsigned int adav80x_mux_values[] = {
|
||||
0, 2, 3,
|
||||
};
|
||||
|
||||
#define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \
|
||||
SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \
|
||||
ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \
|
||||
adav80x_mux_values)
|
||||
|
||||
static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0);
|
||||
static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);
|
||||
static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);
|
||||
|
||||
static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl =
|
||||
SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum);
|
||||
static const struct snd_kcontrol_new adav80x_capture_mux_ctrl =
|
||||
SOC_DAPM_ENUM("Route", adav80x_capture_enum);
|
||||
static const struct snd_kcontrol_new adav80x_dac_mux_ctrl =
|
||||
SOC_DAPM_ENUM("Route", adav80x_dac_enum);
|
||||
|
||||
#define ADAV80X_MUX(name, ctrl) \
|
||||
SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
|
||||
|
||||
static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1),
|
||||
|
||||
SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl),
|
||||
ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl),
|
||||
ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl),
|
||||
|
||||
SND_SOC_DAPM_INPUT("VINR"),
|
||||
SND_SOC_DAPM_INPUT("VINL"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTL"),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0),
|
||||
};
|
||||
|
||||
static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
const char *clk;
|
||||
|
||||
switch (adav80x->clk_src) {
|
||||
case ADAV80X_CLK_PLL1:
|
||||
clk = "PLL1";
|
||||
break;
|
||||
case ADAV80X_CLK_PLL2:
|
||||
clk = "PLL2";
|
||||
break;
|
||||
case ADAV80X_CLK_XTAL:
|
||||
clk = "OSC";
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strcmp(source->name, clk) == 0;
|
||||
}
|
||||
|
||||
static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_route adav80x_dapm_routes[] = {
|
||||
{ "DAC Select", "ADC", "ADC" },
|
||||
{ "DAC Select", "Playback", "AIFIN" },
|
||||
{ "DAC Select", "Aux Playback", "AIFAUXIN" },
|
||||
{ "DAC", NULL, "DAC Select" },
|
||||
|
||||
{ "Capture Select", "ADC", "ADC" },
|
||||
{ "Capture Select", "Playback", "AIFIN" },
|
||||
{ "Capture Select", "Aux Playback", "AIFAUXIN" },
|
||||
{ "AIFOUT", NULL, "Capture Select" },
|
||||
|
||||
{ "Aux Capture Select", "ADC", "ADC" },
|
||||
{ "Aux Capture Select", "Playback", "AIFIN" },
|
||||
{ "Aux Capture Select", "Aux Playback", "AIFAUXIN" },
|
||||
{ "AIFAUXOUT", NULL, "Aux Capture Select" },
|
||||
|
||||
{ "VOUTR", NULL, "DAC" },
|
||||
{ "VOUTL", NULL, "DAC" },
|
||||
|
||||
{ "Left PGA", NULL, "VINL" },
|
||||
{ "Right PGA", NULL, "VINR" },
|
||||
{ "ADC", NULL, "Left PGA" },
|
||||
{ "ADC", NULL, "Right PGA" },
|
||||
|
||||
{ "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check },
|
||||
{ "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check },
|
||||
{ "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check },
|
||||
{ "PLL1", NULL, "OSC", adav80x_dapm_pll_check },
|
||||
{ "PLL2", NULL, "OSC", adav80x_dapm_pll_check },
|
||||
|
||||
{ "ADC", NULL, "SYSCLK" },
|
||||
{ "DAC", NULL, "SYSCLK" },
|
||||
{ "AIFOUT", NULL, "SYSCLK" },
|
||||
{ "AIFAUXOUT", NULL, "SYSCLK" },
|
||||
{ "AIFIN", NULL, "SYSCLK" },
|
||||
{ "AIFAUXIN", NULL, "SYSCLK" },
|
||||
};
|
||||
|
||||
static int adav80x_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (adav80x->deemph) {
|
||||
switch (adav80x->rate) {
|
||||
case 32000:
|
||||
val = ADAV80X_DAC_CTRL2_DEEMPH_32;
|
||||
break;
|
||||
case 44100:
|
||||
val = ADAV80X_DAC_CTRL2_DEEMPH_44;
|
||||
break;
|
||||
case 48000:
|
||||
case 64000:
|
||||
case 88200:
|
||||
case 96000:
|
||||
val = ADAV80X_DAC_CTRL2_DEEMPH_48;
|
||||
break;
|
||||
default:
|
||||
val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
|
||||
}
|
||||
|
||||
return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
|
||||
ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);
|
||||
}
|
||||
|
||||
static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int deemph = ucontrol->value.integer.value[0];
|
||||
|
||||
if (deemph > 1)
|
||||
return -EINVAL;
|
||||
|
||||
adav80x->deemph = deemph;
|
||||
|
||||
return adav80x_set_deemph(codec);
|
||||
}
|
||||
|
||||
static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = adav80x->deemph;
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0);
|
||||
static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0);
|
||||
|
||||
static const struct snd_kcontrol_new adav80x_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL,
|
||||
ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL,
|
||||
ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL,
|
||||
ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv),
|
||||
|
||||
SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0),
|
||||
SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1),
|
||||
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0,
|
||||
adav80x_get_deemph, adav80x_put_deemph),
|
||||
};
|
||||
|
||||
static unsigned int adav80x_port_ctrl_regs[2][2] = {
|
||||
{ ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, },
|
||||
{ ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL },
|
||||
};
|
||||
|
||||
static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int capture = 0x00;
|
||||
unsigned int playback = 0x00;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
capture |= ADAV80X_CAPTURE_MODE_MASTER;
|
||||
playback |= ADAV80X_PLAYBACK_MODE_MASTER;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
capture |= ADAV80X_CAPTURE_MODE_I2S;
|
||||
playback |= ADAV80X_PLAYBACK_MODE_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
capture |= ADAV80X_CAPTURE_MODE_LEFT_J;
|
||||
playback |= ADAV80X_PLAYBACK_MODE_LEFT_J;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
capture |= ADAV80X_CAPTURE_MODE_RIGHT_J;
|
||||
playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
|
||||
ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,
|
||||
capture);
|
||||
regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
|
||||
playback);
|
||||
|
||||
adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
|
||||
unsigned int sample_rate)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (sample_rate <= 48000)
|
||||
val = ADAV80X_ADC_CTRL1_MODULATOR_128FS;
|
||||
else
|
||||
val = ADAV80X_ADC_CTRL1_MODULATOR_64FS;
|
||||
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1,
|
||||
ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
|
||||
unsigned int sample_rate)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (sample_rate <= 48000)
|
||||
val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS;
|
||||
else
|
||||
val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS;
|
||||
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
|
||||
ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,
|
||||
val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val = ADAV80X_CAPTURE_WORD_LEN16;
|
||||
break;
|
||||
case 18:
|
||||
val = ADAV80X_CAPTRUE_WORD_LEN18;
|
||||
break;
|
||||
case 20:
|
||||
val = ADAV80X_CAPTURE_WORD_LEN20;
|
||||
break;
|
||||
case 24:
|
||||
val = ADAV80X_CAPTURE_WORD_LEN24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
|
||||
ADAV80X_CAPTURE_WORD_LEN_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
|
||||
return 0;
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;
|
||||
break;
|
||||
case 18:
|
||||
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;
|
||||
break;
|
||||
case 20:
|
||||
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;
|
||||
break;
|
||||
case 24:
|
||||
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
|
||||
ADAV80X_PLAYBACK_MODE_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int rate = params_rate(params);
|
||||
|
||||
if (rate * 256 != adav80x->sysclk)
|
||||
return -EINVAL;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
adav80x_set_playback_pcm_format(codec, dai, params);
|
||||
adav80x_set_dac_clock(codec, rate);
|
||||
} else {
|
||||
adav80x_set_capture_pcm_format(codec, dai, params);
|
||||
adav80x_set_adc_clock(codec, rate);
|
||||
}
|
||||
adav80x->rate = rate;
|
||||
adav80x_set_deemph(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_sysclk(struct snd_soc_codec *codec,
|
||||
int clk_id, int source,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
if (dir == SND_SOC_CLOCK_IN) {
|
||||
switch (clk_id) {
|
||||
case ADAV80X_CLK_XIN:
|
||||
case ADAV80X_CLK_XTAL:
|
||||
case ADAV80X_CLK_MCLKI:
|
||||
case ADAV80X_CLK_PLL1:
|
||||
case ADAV80X_CLK_PLL2:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adav80x->sysclk = freq;
|
||||
|
||||
if (adav80x->clk_src != clk_id) {
|
||||
unsigned int iclk_ctrl1, iclk_ctrl2;
|
||||
|
||||
adav80x->clk_src = clk_id;
|
||||
if (clk_id == ADAV80X_CLK_XTAL)
|
||||
clk_id = ADAV80X_CLK_XIN;
|
||||
|
||||
iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) |
|
||||
ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) |
|
||||
ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);
|
||||
iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id);
|
||||
|
||||
regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1,
|
||||
iclk_ctrl1);
|
||||
regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
|
||||
iclk_ctrl2);
|
||||
|
||||
snd_soc_dapm_sync(dapm);
|
||||
}
|
||||
} else {
|
||||
unsigned int mask;
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAV80X_CLK_SYSCLK1:
|
||||
case ADAV80X_CLK_SYSCLK2:
|
||||
case ADAV80X_CLK_SYSCLK3:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_id -= ADAV80X_CLK_SYSCLK1;
|
||||
mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);
|
||||
|
||||
if (freq == 0) {
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
|
||||
mask, mask);
|
||||
adav80x->sysclk_pd[clk_id] = true;
|
||||
} else {
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
|
||||
mask, 0);
|
||||
adav80x->sysclk_pd[clk_id] = false;
|
||||
}
|
||||
|
||||
snd_soc_dapm_mutex_lock(dapm);
|
||||
|
||||
if (adav80x->sysclk_pd[0])
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1");
|
||||
else
|
||||
snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1");
|
||||
|
||||
if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2])
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2");
|
||||
else
|
||||
snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2");
|
||||
|
||||
snd_soc_dapm_sync_unlocked(dapm);
|
||||
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int pll_ctrl1 = 0;
|
||||
unsigned int pll_ctrl2 = 0;
|
||||
unsigned int pll_src;
|
||||
|
||||
switch (source) {
|
||||
case ADAV80X_PLL_SRC_XTAL:
|
||||
case ADAV80X_PLL_SRC_XIN:
|
||||
case ADAV80X_PLL_SRC_MCLKI:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!freq_out)
|
||||
return 0;
|
||||
|
||||
switch (freq_in) {
|
||||
case 27000000:
|
||||
break;
|
||||
case 54000000:
|
||||
if (source == ADAV80X_PLL_SRC_XIN) {
|
||||
pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (freq_out > 12288000) {
|
||||
pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id);
|
||||
freq_out /= 2;
|
||||
}
|
||||
|
||||
/* freq_out = sample_rate * 256 */
|
||||
switch (freq_out) {
|
||||
case 8192000:
|
||||
pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id);
|
||||
break;
|
||||
case 11289600:
|
||||
pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id);
|
||||
break;
|
||||
case 12288000:
|
||||
pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1,
|
||||
ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2,
|
||||
ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);
|
||||
|
||||
if (source != adav80x->pll_src) {
|
||||
if (source == ADAV80X_PLL_SRC_MCLKI)
|
||||
pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id);
|
||||
else
|
||||
pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id);
|
||||
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC,
|
||||
ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);
|
||||
|
||||
adav80x->pll_src = source;
|
||||
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int mask = ADAV80X_DAC_CTRL1_PD;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
|
||||
0x00);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
|
||||
mask);
|
||||
break;
|
||||
}
|
||||
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enforce the same sample rate on all audio interfaces */
|
||||
static int adav80x_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
|
||||
return 0;
|
||||
|
||||
return snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate);
|
||||
}
|
||||
|
||||
static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!snd_soc_codec_is_active(codec))
|
||||
adav80x->rate = 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops adav80x_dai_ops = {
|
||||
.set_fmt = adav80x_set_dai_fmt,
|
||||
.hw_params = adav80x_hw_params,
|
||||
.startup = adav80x_dai_startup,
|
||||
.shutdown = adav80x_dai_shutdown,
|
||||
};
|
||||
|
||||
#define ADAV80X_PLAYBACK_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)
|
||||
|
||||
#define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static struct snd_soc_dai_driver adav80x_dais[] = {
|
||||
{
|
||||
.name = "adav80x-hifi",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.stream_name = "HiFi Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ADAV80X_PLAYBACK_RATES,
|
||||
.formats = ADAV80X_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "HiFi Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ADAV80X_CAPTURE_RATES,
|
||||
.formats = ADAV80X_FORMATS,
|
||||
},
|
||||
.ops = &adav80x_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "adav80x-aux",
|
||||
.id = 1,
|
||||
.playback = {
|
||||
.stream_name = "Aux Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ADAV80X_PLAYBACK_RATES,
|
||||
.formats = ADAV80X_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Aux Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ADAV80X_CAPTURE_RATES,
|
||||
.formats = ADAV80X_FORMATS,
|
||||
},
|
||||
.ops = &adav80x_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int adav80x_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Force PLLs on for SYSCLK output */
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
|
||||
|
||||
/* Power down S/PDIF receiver, since it is currently not supported */
|
||||
regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
|
||||
/* Disable DAC zero flag */
|
||||
regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adav80x_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_sync(adav80x->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver adav80x_codec_driver = {
|
||||
.probe = adav80x_probe,
|
||||
.resume = adav80x_resume,
|
||||
.set_bias_level = adav80x_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.set_pll = adav80x_set_pll,
|
||||
.set_sysclk = adav80x_set_sysclk,
|
||||
|
||||
.controls = adav80x_controls,
|
||||
.num_controls = ARRAY_SIZE(adav80x_controls),
|
||||
.dapm_widgets = adav80x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets),
|
||||
.dapm_routes = adav80x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
|
||||
};
|
||||
|
||||
int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct adav80x *adav80x;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL);
|
||||
if (!adav80x)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, adav80x);
|
||||
adav80x->regmap = regmap;
|
||||
|
||||
return snd_soc_register_codec(dev, &adav80x_codec_driver,
|
||||
adav80x_dais, ARRAY_SIZE(adav80x_dais));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adav80x_bus_probe);
|
||||
|
||||
const struct regmap_config adav80x_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.pad_bits = 1,
|
||||
.reg_bits = 7,
|
||||
.read_flag_mask = 0x01,
|
||||
|
||||
.max_register = ADAV80X_PLL_OUTE,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = adav80x_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adav80x_regmap_config);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAV80x driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
|
||||
MODULE_LICENSE("GPL");
|
||||
42
sound/soc/codecs/adav80x.h
Normal file
42
sound/soc/codecs/adav80x.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* header file for ADAV80X parts
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef _ADAV80X_H
|
||||
#define _ADAV80X_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device;
|
||||
|
||||
extern const struct regmap_config adav80x_regmap_config;
|
||||
int adav80x_bus_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
enum adav80x_pll_src {
|
||||
ADAV80X_PLL_SRC_XIN,
|
||||
ADAV80X_PLL_SRC_XTAL,
|
||||
ADAV80X_PLL_SRC_MCLKI,
|
||||
};
|
||||
|
||||
enum adav80x_pll {
|
||||
ADAV80X_PLL1 = 0,
|
||||
ADAV80X_PLL2 = 1,
|
||||
};
|
||||
|
||||
enum adav80x_clk_src {
|
||||
ADAV80X_CLK_XIN = 0,
|
||||
ADAV80X_CLK_MCLKI = 1,
|
||||
ADAV80X_CLK_PLL1 = 2,
|
||||
ADAV80X_CLK_PLL2 = 3,
|
||||
ADAV80X_CLK_XTAL = 6,
|
||||
|
||||
ADAV80X_CLK_SYSCLK1 = 6,
|
||||
ADAV80X_CLK_SYSCLK2 = 7,
|
||||
ADAV80X_CLK_SYSCLK3 = 8,
|
||||
};
|
||||
|
||||
#endif
|
||||
92
sound/soc/codecs/ads117x.c
Normal file
92
sound/soc/codecs/ads117x.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* ads117x.c -- Driver for ads1174/8 ADC chips
|
||||
*
|
||||
* Copyright 2009 ShotSpotter Inc.
|
||||
* Author: Graeme Gregory <gg@slimlogic.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("Input1"),
|
||||
SND_SOC_DAPM_INPUT("Input2"),
|
||||
SND_SOC_DAPM_INPUT("Input3"),
|
||||
SND_SOC_DAPM_INPUT("Input4"),
|
||||
SND_SOC_DAPM_INPUT("Input5"),
|
||||
SND_SOC_DAPM_INPUT("Input6"),
|
||||
SND_SOC_DAPM_INPUT("Input7"),
|
||||
SND_SOC_DAPM_INPUT("Input8"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ads117x_dapm_routes[] = {
|
||||
{ "Capture", NULL, "Input1" },
|
||||
{ "Capture", NULL, "Input2" },
|
||||
{ "Capture", NULL, "Input3" },
|
||||
{ "Capture", NULL, "Input4" },
|
||||
{ "Capture", NULL, "Input5" },
|
||||
{ "Capture", NULL, "Input6" },
|
||||
{ "Capture", NULL, "Input7" },
|
||||
{ "Capture", NULL, "Input8" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ads117x_dai = {
|
||||
/* ADC */
|
||||
.name = "ads117x-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 32,
|
||||
.rates = ADS117X_RATES,
|
||||
.formats = ADS117X_FORMATS,},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
|
||||
.dapm_widgets = ads117x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
|
||||
.dapm_routes = ads117x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
|
||||
};
|
||||
|
||||
static int ads117x_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ads117x, &ads117x_dai, 1);
|
||||
}
|
||||
|
||||
static int ads117x_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ads117x_codec_driver = {
|
||||
.driver = {
|
||||
.name = "ads117x-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = ads117x_probe,
|
||||
.remove = ads117x_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ads117x_codec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ads117x driver");
|
||||
MODULE_AUTHOR("Graeme Gregory");
|
||||
MODULE_LICENSE("GPL");
|
||||
360
sound/soc/codecs/ak4104.c
Normal file
360
sound/soc/codecs/ak4104.c
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* AK4104 ALSA SoC (ASoC) driver
|
||||
*
|
||||
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
/* AK4104 registers addresses */
|
||||
#define AK4104_REG_CONTROL1 0x00
|
||||
#define AK4104_REG_RESERVED 0x01
|
||||
#define AK4104_REG_CONTROL2 0x02
|
||||
#define AK4104_REG_TX 0x03
|
||||
#define AK4104_REG_CHN_STATUS(x) ((x) + 0x04)
|
||||
#define AK4104_NUM_REGS 10
|
||||
|
||||
#define AK4104_REG_MASK 0x1f
|
||||
#define AK4104_READ 0xc0
|
||||
#define AK4104_WRITE 0xe0
|
||||
#define AK4104_RESERVED_VAL 0x5b
|
||||
|
||||
/* Bit masks for AK4104 registers */
|
||||
#define AK4104_CONTROL1_RSTN (1 << 0)
|
||||
#define AK4104_CONTROL1_PW (1 << 1)
|
||||
#define AK4104_CONTROL1_DIF0 (1 << 2)
|
||||
#define AK4104_CONTROL1_DIF1 (1 << 3)
|
||||
|
||||
#define AK4104_CONTROL2_SEL0 (1 << 0)
|
||||
#define AK4104_CONTROL2_SEL1 (1 << 1)
|
||||
#define AK4104_CONTROL2_MODE (1 << 2)
|
||||
|
||||
#define AK4104_TX_TXE (1 << 0)
|
||||
#define AK4104_TX_V (1 << 1)
|
||||
|
||||
struct ak4104_private {
|
||||
struct regmap *regmap;
|
||||
struct regulator *regulator;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
|
||||
{ "TXE", NULL, "Playback" },
|
||||
{ "TX", NULL, "TXE" },
|
||||
};
|
||||
|
||||
static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int val = 0;
|
||||
int ret;
|
||||
|
||||
/* set DAI format */
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val |= AK4104_CONTROL1_DIF0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "invalid dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* This device can only be slave */
|
||||
if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
|
||||
val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, val = 0;
|
||||
|
||||
/* set the IEC958 bits: consumer mode, no copyright bit */
|
||||
val |= IEC958_AES0_CON_NOT_COPYRIGHT;
|
||||
regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
|
||||
|
||||
val = 0;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 22050:
|
||||
val |= IEC958_AES3_CON_FS_22050;
|
||||
break;
|
||||
case 24000:
|
||||
val |= IEC958_AES3_CON_FS_24000;
|
||||
break;
|
||||
case 32000:
|
||||
val |= IEC958_AES3_CON_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
val |= IEC958_AES3_CON_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
val |= IEC958_AES3_CON_FS_48000;
|
||||
break;
|
||||
case 88200:
|
||||
val |= IEC958_AES3_CON_FS_88200;
|
||||
break;
|
||||
case 96000:
|
||||
val |= IEC958_AES3_CON_FS_96000;
|
||||
break;
|
||||
case 176400:
|
||||
val |= IEC958_AES3_CON_FS_176400;
|
||||
break;
|
||||
case 192000:
|
||||
val |= IEC958_AES3_CON_FS_192000;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported sampling rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak4101_dai_ops = {
|
||||
.hw_params = ak4104_hw_params,
|
||||
.set_fmt = ak4104_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4104_dai = {
|
||||
.name = "ak4104-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE
|
||||
},
|
||||
.ops = &ak4101_dai_ops,
|
||||
};
|
||||
|
||||
static int ak4104_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(ak4104->regulator);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Unable to enable regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set power-up and non-reset bits */
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
|
||||
if (ret < 0)
|
||||
goto exit_disable_regulator;
|
||||
|
||||
/* enable transmitter */
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, AK4104_TX_TXE);
|
||||
if (ret < 0)
|
||||
goto exit_disable_regulator;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_disable_regulator:
|
||||
regulator_disable(ak4104->regulator);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4104_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
|
||||
regulator_disable(ak4104->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ak4104_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regulator_disable(priv->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(priv->regulator);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ak4104_soc_suspend NULL
|
||||
#define ak4104_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
|
||||
.probe = ak4104_probe,
|
||||
.remove = ak4104_remove,
|
||||
.suspend = ak4104_soc_suspend,
|
||||
.resume = ak4104_soc_resume,
|
||||
|
||||
.dapm_widgets = ak4104_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
|
||||
.dapm_routes = ak4104_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4104_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = AK4104_NUM_REGS - 1,
|
||||
.read_flag_mask = AK4104_READ,
|
||||
.write_flag_mask = AK4104_WRITE,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int ak4104_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
struct ak4104_private *ak4104;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_0;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
|
||||
GFP_KERNEL);
|
||||
if (ak4104 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
|
||||
if (IS_ERR(ak4104->regulator)) {
|
||||
ret = PTR_ERR(ak4104->regulator);
|
||||
dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
|
||||
if (IS_ERR(ak4104->regmap)) {
|
||||
ret = PTR_ERR(ak4104->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (np) {
|
||||
enum of_gpio_flags flags;
|
||||
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
|
||||
|
||||
if (gpio_is_valid(gpio)) {
|
||||
ret = devm_gpio_request_one(&spi->dev, gpio,
|
||||
flags & OF_GPIO_ACTIVE_LOW ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
|
||||
"ak4104 reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* read the 'reserved' register - according to the datasheet, it
|
||||
* should contain 0x5b. Not a good way to verify the presence of
|
||||
* the device, but there is no hardware ID register. */
|
||||
ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (val != AK4104_RESERVED_VAL)
|
||||
return -ENODEV;
|
||||
|
||||
spi_set_drvdata(spi, ak4104);
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_device_ak4104, &ak4104_dai, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4104_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ak4104_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak4104", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4104_of_match);
|
||||
|
||||
static const struct spi_device_id ak4104_id_table[] = {
|
||||
{ "ak4104", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ak4104_id_table);
|
||||
|
||||
static struct spi_driver ak4104_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ak4104",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ak4104_of_match,
|
||||
},
|
||||
.id_table = ak4104_id_table,
|
||||
.probe = ak4104_spi_probe,
|
||||
.remove = ak4104_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(ak4104_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
|
||||
MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
482
sound/soc/codecs/ak4535.c
Normal file
482
sound/soc/codecs/ak4535.c
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
/*
|
||||
* ak4535.c -- AK4535 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Author: Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* Based on wm8753.c by Liam Girdwood
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "ak4535.h"
|
||||
|
||||
/* codec private data */
|
||||
struct ak4535_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int sysclk;
|
||||
};
|
||||
|
||||
/*
|
||||
* ak4535 register cache
|
||||
*/
|
||||
static const struct reg_default ak4535_reg_defaults[] = {
|
||||
{ 0, 0x00 },
|
||||
{ 1, 0x80 },
|
||||
{ 2, 0x00 },
|
||||
{ 3, 0x03 },
|
||||
{ 4, 0x02 },
|
||||
{ 5, 0x00 },
|
||||
{ 6, 0x11 },
|
||||
{ 7, 0x01 },
|
||||
{ 8, 0x00 },
|
||||
{ 9, 0x40 },
|
||||
{ 10, 0x36 },
|
||||
{ 11, 0x10 },
|
||||
{ 12, 0x00 },
|
||||
{ 13, 0x00 },
|
||||
{ 14, 0x57 },
|
||||
};
|
||||
|
||||
static bool ak4535_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case AK4535_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
|
||||
static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"};
|
||||
static const char *ak4535_hp_out[] = {"Stereo", "Mono"};
|
||||
static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"};
|
||||
static const char *ak4535_mic_select[] = {"Internal", "External"};
|
||||
|
||||
static const struct soc_enum ak4535_enum[] = {
|
||||
SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain),
|
||||
SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out),
|
||||
SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out),
|
||||
SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp),
|
||||
SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4535_snd_controls[] = {
|
||||
SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0),
|
||||
SOC_ENUM("Mono 1 Output", ak4535_enum[1]),
|
||||
SOC_ENUM("Mono 1 Gain", ak4535_enum[0]),
|
||||
SOC_ENUM("Headphone Output", ak4535_enum[2]),
|
||||
SOC_ENUM("Playback Deemphasis", ak4535_enum[3]),
|
||||
SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0),
|
||||
SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0),
|
||||
SOC_ENUM("Mic Select", ak4535_enum[4]),
|
||||
SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0),
|
||||
SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0),
|
||||
SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0),
|
||||
SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0),
|
||||
SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0),
|
||||
SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0),
|
||||
SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0),
|
||||
SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1),
|
||||
SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1),
|
||||
SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0),
|
||||
SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
|
||||
};
|
||||
|
||||
/* Mono 1 Mixer */
|
||||
static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Stereo Mixer */
|
||||
static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Input Mixer */
|
||||
static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Input mux */
|
||||
static const struct snd_kcontrol_new ak4535_input_mux_control =
|
||||
SOC_DAPM_ENUM("Input Select", ak4535_enum[4]);
|
||||
|
||||
/* HP L switch */
|
||||
static const struct snd_kcontrol_new ak4535_hpl_control =
|
||||
SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1);
|
||||
|
||||
/* HP R switch */
|
||||
static const struct snd_kcontrol_new ak4535_hpr_control =
|
||||
SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1);
|
||||
|
||||
/* mono 2 switch */
|
||||
static const struct snd_kcontrol_new ak4535_mono2_control =
|
||||
SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0);
|
||||
|
||||
/* Line out switch */
|
||||
static const struct snd_kcontrol_new ak4535_line_control =
|
||||
SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0);
|
||||
|
||||
/* ak4535 dapm widgets */
|
||||
static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_stereo_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4535_stereo_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_mono1_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4535_mono1_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_input_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4535_input_mixer_controls)),
|
||||
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_input_mux_control),
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0),
|
||||
SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_mono2_control),
|
||||
/* speaker powersave bit */
|
||||
SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_line_control),
|
||||
SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_hpl_control),
|
||||
SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4535_hpr_control),
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("HPL"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
SND_SOC_DAPM_OUTPUT("HPR"),
|
||||
SND_SOC_DAPM_OUTPUT("SPP"),
|
||||
SND_SOC_DAPM_OUTPUT("SPN"),
|
||||
SND_SOC_DAPM_OUTPUT("MOUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("MOUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("MICOUT"),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0),
|
||||
SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0),
|
||||
SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0),
|
||||
SND_SOC_DAPM_INPUT("MICIN"),
|
||||
SND_SOC_DAPM_INPUT("MICEXT"),
|
||||
SND_SOC_DAPM_INPUT("AUX"),
|
||||
SND_SOC_DAPM_INPUT("MIN"),
|
||||
SND_SOC_DAPM_INPUT("AIN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4535_audio_map[] = {
|
||||
/*stereo mixer */
|
||||
{"Stereo Mixer", "Playback Switch", "DAC"},
|
||||
{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
|
||||
{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
|
||||
|
||||
/* mono1 mixer */
|
||||
{"Mono1 Mixer", "Mic Sidetone Switch", "Mic"},
|
||||
{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
|
||||
|
||||
/* Mic */
|
||||
{"Mic", NULL, "AIN"},
|
||||
{"Input Mux", "Internal", "Mic Int Bias"},
|
||||
{"Input Mux", "External", "Mic Ext Bias"},
|
||||
{"Mic Int Bias", NULL, "MICIN"},
|
||||
{"Mic Ext Bias", NULL, "MICEXT"},
|
||||
{"MICOUT", NULL, "Input Mux"},
|
||||
|
||||
/* line out */
|
||||
{"LOUT", NULL, "Line Out Enable"},
|
||||
{"ROUT", NULL, "Line Out Enable"},
|
||||
{"Line Out Enable", "Switch", "Line Out"},
|
||||
{"Line Out", NULL, "Stereo Mixer"},
|
||||
|
||||
/* mono1 out */
|
||||
{"MOUT1", NULL, "Mono Out"},
|
||||
{"Mono Out", NULL, "Mono1 Mixer"},
|
||||
|
||||
/* left HP */
|
||||
{"HPL", NULL, "Left HP Enable"},
|
||||
{"Left HP Enable", "Switch", "HP L Amp"},
|
||||
{"HP L Amp", NULL, "Stereo Mixer"},
|
||||
|
||||
/* right HP */
|
||||
{"HPR", NULL, "Right HP Enable"},
|
||||
{"Right HP Enable", "Switch", "HP R Amp"},
|
||||
{"HP R Amp", NULL, "Stereo Mixer"},
|
||||
|
||||
/* speaker */
|
||||
{"SPP", NULL, "Speaker Enable"},
|
||||
{"SPN", NULL, "Speaker Enable"},
|
||||
{"Speaker Enable", "Switch", "Spk Amp"},
|
||||
{"Spk Amp", NULL, "MIN"},
|
||||
|
||||
/* mono 2 */
|
||||
{"MOUT2", NULL, "Mono 2 Enable"},
|
||||
{"Mono 2 Enable", "Switch", "Stereo Mixer"},
|
||||
|
||||
/* Aux In */
|
||||
{"Aux In", NULL, "AUX"},
|
||||
|
||||
/* ADC */
|
||||
{"ADC", NULL, "Input Mixer"},
|
||||
{"Input Mixer", "Mic Capture Switch", "Mic"},
|
||||
{"Input Mixer", "Aux Capture Switch", "Aux In"},
|
||||
};
|
||||
|
||||
static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ak4535->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
|
||||
int rate = params_rate(params), fs = 256;
|
||||
|
||||
if (rate)
|
||||
fs = ak4535->sysclk / rate;
|
||||
|
||||
/* set fs */
|
||||
switch (fs) {
|
||||
case 1024:
|
||||
mode2 |= (0x2 << 5);
|
||||
break;
|
||||
case 512:
|
||||
mode2 |= (0x1 << 5);
|
||||
break;
|
||||
case 256:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set rate */
|
||||
snd_soc_write(codec, AK4535_MODE2, mode2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u8 mode1 = 0;
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
mode1 = 0x0002;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
mode1 = 0x0001;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* use 32 fs for BCLK to save power */
|
||||
mode1 |= 0x4;
|
||||
|
||||
snd_soc_write(codec, AK4535_MODE1, mode1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u16 mute_reg = snd_soc_read(codec, AK4535_DAC);
|
||||
if (!mute)
|
||||
snd_soc_write(codec, AK4535_DAC, mute_reg & ~0x20);
|
||||
else
|
||||
snd_soc_write(codec, AK4535_DAC, mute_reg | 0x20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0x20);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0x80);
|
||||
snd_soc_update_bits(codec, AK4535_PM2, 0x80, 0);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
|
||||
|
||||
static const struct snd_soc_dai_ops ak4535_dai_ops = {
|
||||
.hw_params = ak4535_hw_params,
|
||||
.set_fmt = ak4535_set_dai_fmt,
|
||||
.digital_mute = ak4535_mute,
|
||||
.set_sysclk = ak4535_set_dai_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4535_dai = {
|
||||
.name = "ak4535-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4535_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4535_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||
.ops = &ak4535_dai_ops,
|
||||
};
|
||||
|
||||
static int ak4535_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_cache_sync(codec);
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* power on device */
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
snd_soc_add_codec_controls(codec, ak4535_snd_controls,
|
||||
ARRAY_SIZE(ak4535_snd_controls));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ak4535_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config ak4535_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = AK4535_STATUS,
|
||||
.volatile_reg = ak4535_volatile,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = ak4535_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
|
||||
.probe = ak4535_probe,
|
||||
.remove = ak4535_remove,
|
||||
.suspend = ak4535_suspend,
|
||||
.resume = ak4535_resume,
|
||||
.set_bias_level = ak4535_set_bias_level,
|
||||
.dapm_widgets = ak4535_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
|
||||
.dapm_routes = ak4535_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
|
||||
};
|
||||
|
||||
static int ak4535_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ak4535_priv *ak4535;
|
||||
int ret;
|
||||
|
||||
ak4535 = devm_kzalloc(&i2c->dev, sizeof(struct ak4535_priv),
|
||||
GFP_KERNEL);
|
||||
if (ak4535 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap);
|
||||
if (IS_ERR(ak4535->regmap)) {
|
||||
ret = PTR_ERR(ak4535->regmap);
|
||||
dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, ak4535);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_ak4535, &ak4535_dai, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4535_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak4535_i2c_id[] = {
|
||||
{ "ak4535", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
|
||||
|
||||
static struct i2c_driver ak4535_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4535",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4535_i2c_probe,
|
||||
.remove = ak4535_i2c_remove,
|
||||
.id_table = ak4535_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ak4535_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Soc AK4535 driver");
|
||||
MODULE_AUTHOR("Richard Purdie");
|
||||
MODULE_LICENSE("GPL");
|
||||
37
sound/soc/codecs/ak4535.h
Normal file
37
sound/soc/codecs/ak4535.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* ak4535.h -- AK4535 Soc Audio driver
|
||||
*
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Author: Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* Based on wm8753.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _AK4535_H
|
||||
#define _AK4535_H
|
||||
|
||||
/* AK4535 register space */
|
||||
|
||||
#define AK4535_PM1 0x0
|
||||
#define AK4535_PM2 0x1
|
||||
#define AK4535_SIG1 0x2
|
||||
#define AK4535_SIG2 0x3
|
||||
#define AK4535_MODE1 0x4
|
||||
#define AK4535_MODE2 0x5
|
||||
#define AK4535_DAC 0x6
|
||||
#define AK4535_MIC 0x7
|
||||
#define AK4535_TIMER 0x8
|
||||
#define AK4535_ALC1 0x9
|
||||
#define AK4535_ALC2 0xa
|
||||
#define AK4535_PGA 0xb
|
||||
#define AK4535_LATT 0xc
|
||||
#define AK4535_RATT 0xd
|
||||
#define AK4535_VOL 0xe
|
||||
#define AK4535_STATUS 0xf
|
||||
|
||||
#endif
|
||||
106
sound/soc/codecs/ak4554.c
Normal file
106
sound/soc/codecs/ak4554.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* ak4554.c
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
/*
|
||||
* ak4554 is very simple DA/AD converter which has no setting register.
|
||||
*
|
||||
* CAUTION
|
||||
*
|
||||
* ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J,
|
||||
* and, capture format is SND_SOC_DAIFMT_LEFT_J
|
||||
* on same bit clock, LR clock.
|
||||
* But, this driver doesn't have snd_soc_dai_ops :: set_fmt
|
||||
*
|
||||
* CPU/Codec DAI image
|
||||
*
|
||||
* CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554
|
||||
* |
|
||||
* CPU-DAI2 (capture only fmt = LEFT_J) ---+
|
||||
*/
|
||||
|
||||
static const struct snd_soc_dapm_widget ak4554_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("AINL"),
|
||||
SND_SOC_DAPM_INPUT("AINR"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4554_dapm_routes[] = {
|
||||
{ "Capture", NULL, "AINL" },
|
||||
{ "Capture", NULL, "AINR" },
|
||||
|
||||
{ "AOUTL", NULL, "Playback" },
|
||||
{ "AOUTR", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4554_dai = {
|
||||
.name = "ak4554-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
|
||||
.dapm_widgets = ak4554_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
|
||||
.dapm_routes = ak4554_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes),
|
||||
};
|
||||
|
||||
static int ak4554_soc_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_ak4554,
|
||||
&ak4554_dai, 1);
|
||||
}
|
||||
|
||||
static int ak4554_soc_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id ak4554_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak4554" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4554_of_match);
|
||||
|
||||
static struct platform_driver ak4554_driver = {
|
||||
.driver = {
|
||||
.name = "ak4554-adc-dac",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ak4554_of_match,
|
||||
},
|
||||
.probe = ak4554_soc_probe,
|
||||
.remove = ak4554_soc_remove,
|
||||
};
|
||||
module_platform_driver(ak4554_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SoC AK4554 driver");
|
||||
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
||||
655
sound/soc/codecs/ak4641.c
Normal file
655
sound/soc/codecs/ak4641.c
Normal file
|
|
@ -0,0 +1,655 @@
|
|||
/*
|
||||
* ak4641.c -- AK4641 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright (C) 2008 Harald Welte <laforge@gnufiish.org>
|
||||
* Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru>
|
||||
*
|
||||
* Based on ak4535.c by Richard Purdie
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/ak4641.h>
|
||||
|
||||
#include "ak4641.h"
|
||||
|
||||
/* codec private data */
|
||||
struct ak4641_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int sysclk;
|
||||
int deemph;
|
||||
int playback_fs;
|
||||
};
|
||||
|
||||
/*
|
||||
* ak4641 register cache
|
||||
*/
|
||||
static const struct reg_default ak4641_reg_defaults[] = {
|
||||
{ 0, 0x00 }, { 1, 0x80 }, { 2, 0x00 }, { 3, 0x80 },
|
||||
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x11 }, { 7, 0x05 },
|
||||
{ 8, 0x00 }, { 9, 0x00 }, { 10, 0x36 }, { 11, 0x10 },
|
||||
{ 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 },
|
||||
{ 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }
|
||||
};
|
||||
|
||||
static const int deemph_settings[] = {44100, 0, 48000, 32000};
|
||||
|
||||
static int ak4641_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, best = 0;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
|
||||
/* if deemphasis is on, select the nearest available rate */
|
||||
if (ak4641->deemph && deemph_settings[i] != 0 &&
|
||||
abs(deemph_settings[i] - ak4641->playback_fs) <
|
||||
abs(deemph_settings[best] - ak4641->playback_fs))
|
||||
best = i;
|
||||
|
||||
if (!ak4641->deemph && deemph_settings[i] == 0)
|
||||
best = i;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "Set deemphasis %d\n", best);
|
||||
|
||||
return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best);
|
||||
}
|
||||
|
||||
static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
int deemph = ucontrol->value.integer.value[0];
|
||||
|
||||
if (deemph > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ak4641->deemph = deemph;
|
||||
|
||||
return ak4641_set_deemph(codec);
|
||||
}
|
||||
|
||||
static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = ak4641->deemph;
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"};
|
||||
static const char *ak4641_hp_out[] = {"Stereo", "Mono"};
|
||||
static const char *ak4641_mic_select[] = {"Internal", "External"};
|
||||
static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"};
|
||||
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
|
||||
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum,
|
||||
AK4641_SIG1, 6, ak4641_mono_out);
|
||||
static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum,
|
||||
AK4641_MODE2, 2, ak4641_hp_out);
|
||||
static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum,
|
||||
AK4641_MIC, 1, ak4641_mic_select);
|
||||
static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum,
|
||||
AK4641_BTIF, 4, ak4641_mic_or_dac);
|
||||
|
||||
static const struct snd_kcontrol_new ak4641_snd_controls[] = {
|
||||
SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
|
||||
SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1,
|
||||
mono_gain_tlv),
|
||||
SOC_ENUM("Headphone Output", ak4641_hp_out_enum),
|
||||
SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
|
||||
ak4641_get_deemph, ak4641_put_deemph),
|
||||
|
||||
SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv),
|
||||
|
||||
SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0),
|
||||
SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0),
|
||||
SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0),
|
||||
|
||||
SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv),
|
||||
SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0),
|
||||
SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT,
|
||||
AK4641_RATT, 0, 255, 1, master_tlv),
|
||||
|
||||
SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv),
|
||||
|
||||
SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0),
|
||||
SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv),
|
||||
SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv),
|
||||
SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv),
|
||||
SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv),
|
||||
SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv),
|
||||
};
|
||||
|
||||
/* Mono 1 Mixer */
|
||||
static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0,
|
||||
mic_mono_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Stereo Mixer */
|
||||
static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0,
|
||||
mic_stereo_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Input Mixer */
|
||||
static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Mic mux */
|
||||
static const struct snd_kcontrol_new ak4641_mic_mux_control =
|
||||
SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum);
|
||||
|
||||
/* Input mux */
|
||||
static const struct snd_kcontrol_new ak4641_input_mux_control =
|
||||
SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum);
|
||||
|
||||
/* mono 2 switch */
|
||||
static const struct snd_kcontrol_new ak4641_mono2_control =
|
||||
SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0);
|
||||
|
||||
/* ak4641 dapm widgets */
|
||||
static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_stereo_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4641_stereo_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_mono1_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4641_mono1_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_input_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4641_input_mixer_controls)),
|
||||
SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_mic_mux_control),
|
||||
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_input_mux_control),
|
||||
SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4641_mono2_control),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
SND_SOC_DAPM_OUTPUT("MOUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("MOUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("MICOUT"),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0),
|
||||
SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0),
|
||||
SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
|
||||
SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
|
||||
|
||||
SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
|
||||
SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
|
||||
|
||||
SND_SOC_DAPM_INPUT("MICIN"),
|
||||
SND_SOC_DAPM_INPUT("MICEXT"),
|
||||
SND_SOC_DAPM_INPUT("AUX"),
|
||||
SND_SOC_DAPM_INPUT("AIN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4641_audio_map[] = {
|
||||
/* Stereo Mixer */
|
||||
{"Stereo Mixer", "Playback Switch", "DAC"},
|
||||
{"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"},
|
||||
{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
|
||||
|
||||
/* Mono 1 Mixer */
|
||||
{"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"},
|
||||
{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
|
||||
|
||||
/* Mic */
|
||||
{"Mic", NULL, "AIN"},
|
||||
{"Mic Mux", "Internal", "Mic Int Bias"},
|
||||
{"Mic Mux", "External", "Mic Ext Bias"},
|
||||
{"Mic Int Bias", NULL, "MICIN"},
|
||||
{"Mic Ext Bias", NULL, "MICEXT"},
|
||||
{"MICOUT", NULL, "Mic Mux"},
|
||||
|
||||
/* Input Mux */
|
||||
{"Input Mux", "Microphone", "Mic"},
|
||||
{"Input Mux", "Voice DAC", "Voice DAC"},
|
||||
|
||||
/* Line Out */
|
||||
{"LOUT", NULL, "Line Out"},
|
||||
{"ROUT", NULL, "Line Out"},
|
||||
{"Line Out", NULL, "Stereo Mixer"},
|
||||
|
||||
/* Mono 1 Out */
|
||||
{"MOUT1", NULL, "Mono Out"},
|
||||
{"Mono Out", NULL, "Mono1 Mixer"},
|
||||
|
||||
/* Mono 2 Out */
|
||||
{"MOUT2", NULL, "Mono 2 Enable"},
|
||||
{"Mono 2 Enable", "Switch", "Mono Out 2"},
|
||||
{"Mono Out 2", NULL, "Stereo Mixer"},
|
||||
|
||||
{"Voice ADC", NULL, "Mono 2 Enable"},
|
||||
|
||||
/* Aux In */
|
||||
{"AUX In", NULL, "AUX"},
|
||||
|
||||
/* ADC */
|
||||
{"ADC", NULL, "Input Mixer"},
|
||||
{"Input Mixer", "Mic Capture Switch", "Mic"},
|
||||
{"Input Mixer", "Aux Capture Switch", "AUX In"},
|
||||
};
|
||||
|
||||
static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ak4641->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
int rate = params_rate(params), fs = 256;
|
||||
u8 mode2;
|
||||
|
||||
if (rate)
|
||||
fs = ak4641->sysclk / rate;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* set fs */
|
||||
switch (fs) {
|
||||
case 1024:
|
||||
mode2 = (0x2 << 5);
|
||||
break;
|
||||
case 512:
|
||||
mode2 = (0x1 << 5);
|
||||
break;
|
||||
case 256:
|
||||
mode2 = (0x0 << 5);
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Error: unsupported fs=%d\n", fs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2);
|
||||
|
||||
/* Update de-emphasis filter for the new rate */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ak4641->playback_fs = rate;
|
||||
ak4641_set_deemph(codec);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u8 btif;
|
||||
int ret;
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
btif = (0x3 << 5);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
btif = (0x2 << 5);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A: /* MSB after FRM */
|
||||
btif = (0x0 << 5);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B: /* MSB during FRM */
|
||||
btif = (0x1 << 5);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u8 mode1 = 0;
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
mode1 = 0x02;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
mode1 = 0x01;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_write(codec, AK4641_MODE1, mode1);
|
||||
}
|
||||
|
||||
static int ak4641_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
|
||||
}
|
||||
|
||||
static int ak4641_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
|
||||
struct ak4641_platform_data *pdata = codec->dev->platform_data;
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
/* unmute */
|
||||
snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* mute */
|
||||
snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
if (pdata && gpio_is_valid(pdata->gpio_power))
|
||||
gpio_set_value(pdata->gpio_power, 1);
|
||||
mdelay(1);
|
||||
if (pdata && gpio_is_valid(pdata->gpio_npdn))
|
||||
gpio_set_value(pdata->gpio_npdn, 1);
|
||||
mdelay(1);
|
||||
|
||||
ret = regcache_sync(ak4641->regmap);
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to sync cache: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80);
|
||||
snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0);
|
||||
if (pdata && gpio_is_valid(pdata->gpio_npdn))
|
||||
gpio_set_value(pdata->gpio_npdn, 0);
|
||||
if (pdata && gpio_is_valid(pdata->gpio_power))
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
regcache_mark_dirty(ak4641->regmap);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define AK4641_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000)
|
||||
#define AK4641_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
|
||||
.hw_params = ak4641_i2s_hw_params,
|
||||
.set_fmt = ak4641_i2s_set_dai_fmt,
|
||||
.digital_mute = ak4641_mute,
|
||||
.set_sysclk = ak4641_set_dai_sysclk,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
|
||||
.hw_params = NULL, /* rates are controlled by BT chip */
|
||||
.set_fmt = ak4641_pcm_set_dai_fmt,
|
||||
.digital_mute = ak4641_mute,
|
||||
.set_sysclk = ak4641_set_dai_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4641_dai[] = {
|
||||
{
|
||||
.name = "ak4641-hifi",
|
||||
.id = 1,
|
||||
.playback = {
|
||||
.stream_name = "HiFi Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4641_RATES,
|
||||
.formats = AK4641_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "HiFi Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4641_RATES,
|
||||
.formats = AK4641_FORMATS,
|
||||
},
|
||||
.ops = &ak4641_i2s_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
},
|
||||
{
|
||||
.name = "ak4641-voice",
|
||||
.id = 1,
|
||||
.playback = {
|
||||
.stream_name = "Voice Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = AK4641_RATES_BT,
|
||||
.formats = AK4641_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Voice Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = AK4641_RATES_BT,
|
||||
.formats = AK4641_FORMATS,
|
||||
},
|
||||
.ops = &ak4641_pcm_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int ak4641_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* power on device */
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
|
||||
.probe = ak4641_probe,
|
||||
.remove = ak4641_remove,
|
||||
.suspend = ak4641_suspend,
|
||||
.resume = ak4641_resume,
|
||||
.controls = ak4641_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4641_snd_controls),
|
||||
.dapm_widgets = ak4641_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4641_dapm_widgets),
|
||||
.dapm_routes = ak4641_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4641_audio_map),
|
||||
.set_bias_level = ak4641_set_bias_level,
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4641_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = AK4641_BTIF,
|
||||
.reg_defaults = ak4641_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int ak4641_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ak4641_platform_data *pdata = i2c->dev.platform_data;
|
||||
struct ak4641_priv *ak4641;
|
||||
int ret;
|
||||
|
||||
ak4641 = devm_kzalloc(&i2c->dev, sizeof(struct ak4641_priv),
|
||||
GFP_KERNEL);
|
||||
if (!ak4641)
|
||||
return -ENOMEM;
|
||||
|
||||
ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap);
|
||||
if (IS_ERR(ak4641->regmap))
|
||||
return PTR_ERR(ak4641->regmap);
|
||||
|
||||
if (pdata) {
|
||||
if (gpio_is_valid(pdata->gpio_power)) {
|
||||
ret = gpio_request_one(pdata->gpio_power,
|
||||
GPIOF_OUT_INIT_LOW, "ak4641 power");
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
if (gpio_is_valid(pdata->gpio_npdn)) {
|
||||
ret = gpio_request_one(pdata->gpio_npdn,
|
||||
GPIOF_OUT_INIT_LOW, "ak4641 npdn");
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
|
||||
udelay(1); /* > 150 ns */
|
||||
gpio_set_value(pdata->gpio_npdn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, ak4641);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
|
||||
ak4641_dai, ARRAY_SIZE(ak4641_dai));
|
||||
if (ret != 0)
|
||||
goto err_gpio2;
|
||||
|
||||
return 0;
|
||||
|
||||
err_gpio2:
|
||||
if (pdata) {
|
||||
if (gpio_is_valid(pdata->gpio_power))
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
if (gpio_is_valid(pdata->gpio_npdn))
|
||||
gpio_free(pdata->gpio_npdn);
|
||||
}
|
||||
err_gpio:
|
||||
if (pdata && gpio_is_valid(pdata->gpio_power))
|
||||
gpio_free(pdata->gpio_power);
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4641_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct ak4641_platform_data *pdata = i2c->dev.platform_data;
|
||||
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
|
||||
if (pdata) {
|
||||
if (gpio_is_valid(pdata->gpio_power)) {
|
||||
gpio_set_value(pdata->gpio_power, 0);
|
||||
gpio_free(pdata->gpio_power);
|
||||
}
|
||||
if (gpio_is_valid(pdata->gpio_npdn))
|
||||
gpio_free(pdata->gpio_npdn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak4641_i2c_id[] = {
|
||||
{ "ak4641", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
|
||||
|
||||
static struct i2c_driver ak4641_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4641",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4641_i2c_probe,
|
||||
.remove = ak4641_i2c_remove,
|
||||
.id_table = ak4641_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ak4641_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("SoC AK4641 driver");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
47
sound/soc/codecs/ak4641.h
Normal file
47
sound/soc/codecs/ak4641.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ak4641.h -- AK4641 SoC Audio driver
|
||||
*
|
||||
* Copyright 2008 Harald Welte <laforge@gnufiish.org>
|
||||
*
|
||||
* Based on ak4535.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _AK4641_H
|
||||
#define _AK4641_H
|
||||
|
||||
/* AK4641 register space */
|
||||
|
||||
#define AK4641_PM1 0x00
|
||||
#define AK4641_PM2 0x01
|
||||
#define AK4641_SIG1 0x02
|
||||
#define AK4641_SIG2 0x03
|
||||
#define AK4641_MODE1 0x04
|
||||
#define AK4641_MODE2 0x05
|
||||
#define AK4641_DAC 0x06
|
||||
#define AK4641_MIC 0x07
|
||||
#define AK4641_TIMER 0x08
|
||||
#define AK4641_ALC1 0x09
|
||||
#define AK4641_ALC2 0x0a
|
||||
#define AK4641_PGA 0x0b
|
||||
#define AK4641_LATT 0x0c
|
||||
#define AK4641_RATT 0x0d
|
||||
#define AK4641_VOL 0x0e
|
||||
#define AK4641_STATUS 0x0f
|
||||
#define AK4641_EQLO 0x10
|
||||
#define AK4641_EQMID 0x11
|
||||
#define AK4641_EQHI 0x12
|
||||
#define AK4641_BTIF 0x13
|
||||
|
||||
#define AK4641_CACHEREGNUM 0x14
|
||||
|
||||
|
||||
|
||||
#define AK4641_DAI_HIFI 0
|
||||
#define AK4641_DAI_VOICE 1
|
||||
|
||||
|
||||
#endif
|
||||
627
sound/soc/codecs/ak4642.c
Normal file
627
sound/soc/codecs/ak4642.c
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright (C) 2009 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
|
||||
*
|
||||
* Based on wm8731.c by Richard Purdie
|
||||
* Based on ak4535.c by Richard Purdie
|
||||
* Based on wm8753.c by Liam Girdwood
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* ** CAUTION **
|
||||
*
|
||||
* This is very simple driver.
|
||||
* It can use headphone output / stereo input only
|
||||
*
|
||||
* AK4642 is tested.
|
||||
* AK4643 is tested.
|
||||
* AK4648 is tested.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#define PW_MGMT1 0x00
|
||||
#define PW_MGMT2 0x01
|
||||
#define SG_SL1 0x02
|
||||
#define SG_SL2 0x03
|
||||
#define MD_CTL1 0x04
|
||||
#define MD_CTL2 0x05
|
||||
#define TIMER 0x06
|
||||
#define ALC_CTL1 0x07
|
||||
#define ALC_CTL2 0x08
|
||||
#define L_IVC 0x09
|
||||
#define L_DVC 0x0a
|
||||
#define ALC_CTL3 0x0b
|
||||
#define R_IVC 0x0c
|
||||
#define R_DVC 0x0d
|
||||
#define MD_CTL3 0x0e
|
||||
#define MD_CTL4 0x0f
|
||||
#define PW_MGMT3 0x10
|
||||
#define DF_S 0x11
|
||||
#define FIL3_0 0x12
|
||||
#define FIL3_1 0x13
|
||||
#define FIL3_2 0x14
|
||||
#define FIL3_3 0x15
|
||||
#define EQ_0 0x16
|
||||
#define EQ_1 0x17
|
||||
#define EQ_2 0x18
|
||||
#define EQ_3 0x19
|
||||
#define EQ_4 0x1a
|
||||
#define EQ_5 0x1b
|
||||
#define FIL1_0 0x1c
|
||||
#define FIL1_1 0x1d
|
||||
#define FIL1_2 0x1e
|
||||
#define FIL1_3 0x1f
|
||||
#define PW_MGMT4 0x20
|
||||
#define MD_CTL5 0x21
|
||||
#define LO_MS 0x22
|
||||
#define HP_MS 0x23
|
||||
#define SPK_MS 0x24
|
||||
|
||||
/* PW_MGMT1*/
|
||||
#define PMVCM (1 << 6) /* VCOM Power Management */
|
||||
#define PMMIN (1 << 5) /* MIN Input Power Management */
|
||||
#define PMDAC (1 << 2) /* DAC Power Management */
|
||||
#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
|
||||
|
||||
/* PW_MGMT2 */
|
||||
#define HPMTN (1 << 6)
|
||||
#define PMHPL (1 << 5)
|
||||
#define PMHPR (1 << 4)
|
||||
#define MS (1 << 3) /* master/slave select */
|
||||
#define MCKO (1 << 1)
|
||||
#define PMPLL (1 << 0)
|
||||
|
||||
#define PMHP_MASK (PMHPL | PMHPR)
|
||||
#define PMHP PMHP_MASK
|
||||
|
||||
/* PW_MGMT3 */
|
||||
#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
|
||||
|
||||
/* SG_SL1 */
|
||||
#define MINS (1 << 6) /* Switch from MIN to Speaker */
|
||||
#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
|
||||
#define PMMP (1 << 2) /* MPWR pin Power Management */
|
||||
#define MGAIN0 (1 << 0) /* MIC amp gain*/
|
||||
|
||||
/* TIMER */
|
||||
#define ZTM(param) ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */
|
||||
#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
|
||||
|
||||
/* ALC_CTL1 */
|
||||
#define ALC (1 << 5) /* ALC Enable */
|
||||
#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
|
||||
|
||||
/* MD_CTL1 */
|
||||
#define PLL3 (1 << 7)
|
||||
#define PLL2 (1 << 6)
|
||||
#define PLL1 (1 << 5)
|
||||
#define PLL0 (1 << 4)
|
||||
#define PLL_MASK (PLL3 | PLL2 | PLL1 | PLL0)
|
||||
|
||||
#define BCKO_MASK (1 << 3)
|
||||
#define BCKO_64 BCKO_MASK
|
||||
|
||||
#define DIF_MASK (3 << 0)
|
||||
#define DSP (0 << 0)
|
||||
#define RIGHT_J (1 << 0)
|
||||
#define LEFT_J (2 << 0)
|
||||
#define I2S (3 << 0)
|
||||
|
||||
/* MD_CTL2 */
|
||||
#define FS0 (1 << 0)
|
||||
#define FS1 (1 << 1)
|
||||
#define FS2 (1 << 2)
|
||||
#define FS3 (1 << 5)
|
||||
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
|
||||
|
||||
/* MD_CTL3 */
|
||||
#define BST1 (1 << 3)
|
||||
|
||||
/* MD_CTL4 */
|
||||
#define DACH (1 << 0)
|
||||
|
||||
struct ak4642_drvdata {
|
||||
const struct regmap_config *regmap_config;
|
||||
int extended_frequencies;
|
||||
};
|
||||
|
||||
struct ak4642_priv {
|
||||
const struct ak4642_drvdata *drvdata;
|
||||
};
|
||||
|
||||
/*
|
||||
* Playback Volume (table 39)
|
||||
*
|
||||
* max : 0x00 : +12.0 dB
|
||||
* ( 0.5 dB step )
|
||||
* min : 0xFE : -115.0 dB
|
||||
* mute: 0xFF
|
||||
*/
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1);
|
||||
|
||||
static const struct snd_kcontrol_new ak4642_snd_controls[] = {
|
||||
|
||||
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
|
||||
0, 0xFF, 1, out_tlv),
|
||||
SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0),
|
||||
SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4642_headphone_control =
|
||||
SOC_DAPM_SINGLE("Switch", PW_MGMT2, 6, 1, 0);
|
||||
|
||||
static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
|
||||
|
||||
/* Outputs */
|
||||
SND_SOC_DAPM_OUTPUT("HPOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("HPOUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("LINEOUT"),
|
||||
|
||||
SND_SOC_DAPM_PGA("HPL Out", PW_MGMT2, 5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("HPR Out", PW_MGMT2, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SWITCH("Headphone Enable", SND_SOC_NOPM, 0, 0,
|
||||
&ak4642_headphone_control),
|
||||
|
||||
SND_SOC_DAPM_PGA("DACH", MD_CTL4, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0,
|
||||
&ak4642_lout_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4642_lout_mixer_controls)),
|
||||
|
||||
/* DAC */
|
||||
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4642_intercon[] = {
|
||||
|
||||
/* Outputs */
|
||||
{"HPOUTL", NULL, "HPL Out"},
|
||||
{"HPOUTR", NULL, "HPR Out"},
|
||||
{"LINEOUT", NULL, "LINEOUT Mixer"},
|
||||
|
||||
{"HPL Out", NULL, "Headphone Enable"},
|
||||
{"HPR Out", NULL, "Headphone Enable"},
|
||||
|
||||
{"Headphone Enable", "Switch", "DACH"},
|
||||
|
||||
{"DACH", NULL, "DAC"},
|
||||
|
||||
{"LINEOUT Mixer", "DACL", "DAC"},
|
||||
};
|
||||
|
||||
/*
|
||||
* ak4642 register cache
|
||||
*/
|
||||
static const struct reg_default ak4642_reg[] = {
|
||||
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
|
||||
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
|
||||
{ 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
|
||||
{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 },
|
||||
{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
|
||||
{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
|
||||
{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
|
||||
{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
|
||||
{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
|
||||
{ 36, 0x00 },
|
||||
};
|
||||
|
||||
static const struct reg_default ak4648_reg[] = {
|
||||
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
|
||||
{ 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
|
||||
{ 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
|
||||
{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 },
|
||||
{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
|
||||
{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
|
||||
{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
|
||||
{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
|
||||
{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
|
||||
{ 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },
|
||||
};
|
||||
|
||||
static int ak4642_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
if (is_play) {
|
||||
/*
|
||||
* start headphone output
|
||||
*
|
||||
* PLL, Master Mode
|
||||
* Audio I/F Format :MSB justified (ADC & DAC)
|
||||
* Bass Boost Level : Middle
|
||||
*
|
||||
* This operation came from example code of
|
||||
* "ASAHI KASEI AK4642" (japanese) manual p97.
|
||||
*/
|
||||
snd_soc_write(codec, L_IVC, 0x91); /* volume */
|
||||
snd_soc_write(codec, R_IVC, 0x91); /* volume */
|
||||
} else {
|
||||
/*
|
||||
* start stereo input
|
||||
*
|
||||
* PLL Master Mode
|
||||
* Audio I/F Format:MSB justified (ADC & DAC)
|
||||
* Pre MIC AMP:+20dB
|
||||
* MIC Power On
|
||||
* ALC setting:Refer to Table 35
|
||||
* ALC bit=“1”
|
||||
*
|
||||
* This operation came from example code of
|
||||
* "ASAHI KASEI AK4642" (japanese) manual p94.
|
||||
*/
|
||||
snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
|
||||
snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
|
||||
snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL);
|
||||
snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
if (is_play) {
|
||||
} else {
|
||||
/* stop stereo input */
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
|
||||
snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
|
||||
snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
u8 pll;
|
||||
int extended_freq = 0;
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
pll = PLL2;
|
||||
break;
|
||||
case 12288000:
|
||||
pll = PLL2 | PLL0;
|
||||
break;
|
||||
case 12000000:
|
||||
pll = PLL2 | PLL1;
|
||||
break;
|
||||
case 24000000:
|
||||
pll = PLL2 | PLL1 | PLL0;
|
||||
break;
|
||||
case 13500000:
|
||||
pll = PLL3 | PLL2;
|
||||
break;
|
||||
case 27000000:
|
||||
pll = PLL3 | PLL2 | PLL0;
|
||||
break;
|
||||
case 19200000:
|
||||
pll = PLL3;
|
||||
extended_freq = 1;
|
||||
break;
|
||||
case 13000000:
|
||||
pll = PLL3 | PLL2 | PLL1;
|
||||
extended_freq = 1;
|
||||
break;
|
||||
case 26000000:
|
||||
pll = PLL3 | PLL2 | PLL1 | PLL0;
|
||||
extended_freq = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (extended_freq && !priv->drvdata->extended_frequencies)
|
||||
return -EINVAL;
|
||||
|
||||
snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 data;
|
||||
u8 bcko;
|
||||
|
||||
data = MCKO | PMPLL; /* use MCKO */
|
||||
bcko = 0;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
data |= MS;
|
||||
bcko = BCKO_64;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, PW_MGMT2, MS | MCKO | PMPLL, data);
|
||||
snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
|
||||
|
||||
/* format type */
|
||||
data = 0;
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
data = LEFT_J;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
data = I2S;
|
||||
break;
|
||||
/* FIXME
|
||||
* Please add RIGHT_J / DSP support here
|
||||
*/
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 rate;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 7350:
|
||||
rate = FS2;
|
||||
break;
|
||||
case 8000:
|
||||
rate = 0;
|
||||
break;
|
||||
case 11025:
|
||||
rate = FS2 | FS0;
|
||||
break;
|
||||
case 12000:
|
||||
rate = FS0;
|
||||
break;
|
||||
case 14700:
|
||||
rate = FS2 | FS1;
|
||||
break;
|
||||
case 16000:
|
||||
rate = FS1;
|
||||
break;
|
||||
case 22050:
|
||||
rate = FS2 | FS1 | FS0;
|
||||
break;
|
||||
case 24000:
|
||||
rate = FS1 | FS0;
|
||||
break;
|
||||
case 29400:
|
||||
rate = FS3 | FS2 | FS1;
|
||||
break;
|
||||
case 32000:
|
||||
rate = FS3 | FS1;
|
||||
break;
|
||||
case 44100:
|
||||
rate = FS3 | FS2 | FS1 | FS0;
|
||||
break;
|
||||
case 48000:
|
||||
rate = FS3 | FS1 | FS0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_write(codec, PW_MGMT1, 0x00);
|
||||
break;
|
||||
default:
|
||||
snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak4642_dai_ops = {
|
||||
.startup = ak4642_dai_startup,
|
||||
.shutdown = ak4642_dai_shutdown,
|
||||
.set_sysclk = ak4642_dai_set_sysclk,
|
||||
.set_fmt = ak4642_dai_set_fmt,
|
||||
.hw_params = ak4642_dai_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4642_dai = {
|
||||
.name = "ak4642-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE },
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE },
|
||||
.ops = &ak4642_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static int ak4642_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
regcache_sync(regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.remove = ak4642_remove,
|
||||
.resume = ak4642_resume,
|
||||
.set_bias_level = ak4642_set_bias_level,
|
||||
.controls = ak4642_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4642_snd_controls),
|
||||
.dapm_widgets = ak4642_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets),
|
||||
.dapm_routes = ak4642_intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4642_intercon),
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4642_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = ARRAY_SIZE(ak4642_reg) + 1,
|
||||
.reg_defaults = ak4642_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(ak4642_reg),
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4648_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = ARRAY_SIZE(ak4648_reg) + 1,
|
||||
.reg_defaults = ak4648_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
|
||||
};
|
||||
|
||||
static const struct ak4642_drvdata ak4642_drvdata = {
|
||||
.regmap_config = &ak4642_regmap,
|
||||
};
|
||||
|
||||
static const struct ak4642_drvdata ak4643_drvdata = {
|
||||
.regmap_config = &ak4642_regmap,
|
||||
};
|
||||
|
||||
static const struct ak4642_drvdata ak4648_drvdata = {
|
||||
.regmap_config = &ak4648_regmap,
|
||||
.extended_frequencies = 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id ak4642_of_match[];
|
||||
static int ak4642_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
const struct ak4642_drvdata *drvdata = NULL;
|
||||
struct regmap *regmap;
|
||||
struct ak4642_priv *priv;
|
||||
|
||||
if (np) {
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(ak4642_of_match, &i2c->dev);
|
||||
if (of_id)
|
||||
drvdata = of_id->data;
|
||||
} else {
|
||||
drvdata = (const struct ak4642_drvdata *)id->driver_data;
|
||||
}
|
||||
|
||||
if (!drvdata) {
|
||||
dev_err(&i2c->dev, "Unknown device type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->drvdata = drvdata;
|
||||
|
||||
i2c_set_clientdata(i2c, priv);
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_ak4642, &ak4642_dai, 1);
|
||||
}
|
||||
|
||||
static int ak4642_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ak4642_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata},
|
||||
{ .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata},
|
||||
{ .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4642_of_match);
|
||||
|
||||
static const struct i2c_device_id ak4642_i2c_id[] = {
|
||||
{ "ak4642", (kernel_ulong_t)&ak4642_drvdata },
|
||||
{ "ak4643", (kernel_ulong_t)&ak4643_drvdata },
|
||||
{ "ak4648", (kernel_ulong_t)&ak4648_drvdata },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
|
||||
|
||||
static struct i2c_driver ak4642_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4642-codec",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ak4642_of_match,
|
||||
},
|
||||
.probe = ak4642_i2c_probe,
|
||||
.remove = ak4642_i2c_remove,
|
||||
.id_table = ak4642_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ak4642_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Soc AK4642 driver");
|
||||
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
691
sound/soc/codecs/ak4671.c
Normal file
691
sound/soc/codecs/ak4671.c
Normal file
|
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
* ak4671.c -- audio driver for AK4671
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ak4671.h"
|
||||
|
||||
|
||||
/* ak4671 register cache & default register settings */
|
||||
static const struct reg_default ak4671_reg_defaults[] = {
|
||||
{ 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */
|
||||
{ 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */
|
||||
{ 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */
|
||||
{ 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */
|
||||
{ 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */
|
||||
{ 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */
|
||||
{ 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */
|
||||
{ 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */
|
||||
{ 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */
|
||||
{ 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */
|
||||
{ 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */
|
||||
{ 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */
|
||||
{ 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */
|
||||
{ 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */
|
||||
{ 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */
|
||||
{ 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */
|
||||
{ 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */
|
||||
{ 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */
|
||||
{ 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */
|
||||
{ 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */
|
||||
{ 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */
|
||||
{ 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */
|
||||
{ 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */
|
||||
{ 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */
|
||||
{ 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */
|
||||
{ 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */
|
||||
{ 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */
|
||||
{ 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */
|
||||
{ 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */
|
||||
{ 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */
|
||||
{ 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */
|
||||
{ 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */
|
||||
{ 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */
|
||||
{ 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */
|
||||
{ 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */
|
||||
{ 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */
|
||||
{ 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */
|
||||
{ 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */
|
||||
{ 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */
|
||||
{ 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */
|
||||
{ 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */
|
||||
{ 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */
|
||||
{ 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */
|
||||
{ 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */
|
||||
{ 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */
|
||||
{ 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */
|
||||
{ 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */
|
||||
{ 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */
|
||||
{ 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */
|
||||
|
||||
{ 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */
|
||||
{ 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */
|
||||
{ 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */
|
||||
{ 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */
|
||||
{ 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */
|
||||
{ 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */
|
||||
{ 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */
|
||||
{ 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */
|
||||
{ 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */
|
||||
{ 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */
|
||||
{ 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */
|
||||
{ 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */
|
||||
{ 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */
|
||||
{ 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */
|
||||
{ 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */
|
||||
{ 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */
|
||||
{ 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */
|
||||
{ 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */
|
||||
{ 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */
|
||||
{ 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */
|
||||
{ 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */
|
||||
{ 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */
|
||||
{ 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */
|
||||
{ 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */
|
||||
{ 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */
|
||||
{ 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */
|
||||
{ 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */
|
||||
{ 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */
|
||||
{ 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */
|
||||
{ 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */
|
||||
{ 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */
|
||||
{ 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */
|
||||
{ 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */
|
||||
{ 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */
|
||||
{ 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */
|
||||
{ 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */
|
||||
{ 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */
|
||||
{ 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */
|
||||
{ 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */
|
||||
{ 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */
|
||||
{ 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */
|
||||
};
|
||||
|
||||
/*
|
||||
* LOUT1/ROUT1 output volume control:
|
||||
* from -24 to 6 dB in 6 dB steps (mute instead of -30 dB)
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1);
|
||||
|
||||
/*
|
||||
* LOUT2/ROUT2 output volume control:
|
||||
* from -33 to 6 dB in 3 dB steps (mute instead of -33 dB)
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1);
|
||||
|
||||
/*
|
||||
* LOUT3/ROUT3 output volume control:
|
||||
* from -6 to 3 dB in 3 dB steps
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0);
|
||||
|
||||
/*
|
||||
* Mic amp gain control:
|
||||
* from -15 to 30 dB in 3 dB steps
|
||||
* REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not
|
||||
* available
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0);
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_snd_controls[] = {
|
||||
/* Common playback gain controls */
|
||||
SOC_SINGLE_TLV("Line Output1 Playback Volume",
|
||||
AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv),
|
||||
SOC_SINGLE_TLV("Headphone Output2 Playback Volume",
|
||||
AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv),
|
||||
SOC_SINGLE_TLV("Line Output3 Playback Volume",
|
||||
AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv),
|
||||
|
||||
/* Common capture gain controls */
|
||||
SOC_DOUBLE_TLV("Mic Amp Capture Volume",
|
||||
AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv),
|
||||
};
|
||||
|
||||
/* event handlers */
|
||||
static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
|
||||
AK4671_MUTEN, AK4671_MUTEN);
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
|
||||
AK4671_MUTEN, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Output Mixers */
|
||||
static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0),
|
||||
};
|
||||
|
||||
/* Input MUXs */
|
||||
static const char *ak4671_lin_mux_texts[] =
|
||||
{"LIN1", "LIN2", "LIN3", "LIN4"};
|
||||
static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum,
|
||||
AK4671_MIC_SIGNAL_SELECT, 0,
|
||||
ak4671_lin_mux_texts);
|
||||
static const struct snd_kcontrol_new ak4671_lin_mux_control =
|
||||
SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
|
||||
|
||||
static const char *ak4671_rin_mux_texts[] =
|
||||
{"RIN1", "RIN2", "RIN3", "RIN4"};
|
||||
static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum,
|
||||
AK4671_MIC_SIGNAL_SELECT, 2,
|
||||
ak4671_rin_mux_texts);
|
||||
static const struct snd_kcontrol_new ak4671_rin_mux_control =
|
||||
SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
|
||||
/* Inputs */
|
||||
SND_SOC_DAPM_INPUT("LIN1"),
|
||||
SND_SOC_DAPM_INPUT("RIN1"),
|
||||
SND_SOC_DAPM_INPUT("LIN2"),
|
||||
SND_SOC_DAPM_INPUT("RIN2"),
|
||||
SND_SOC_DAPM_INPUT("LIN3"),
|
||||
SND_SOC_DAPM_INPUT("RIN3"),
|
||||
SND_SOC_DAPM_INPUT("LIN4"),
|
||||
SND_SOC_DAPM_INPUT("RIN4"),
|
||||
|
||||
/* Outputs */
|
||||
SND_SOC_DAPM_OUTPUT("LOUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUT3"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT3"),
|
||||
|
||||
/* DAC */
|
||||
SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback",
|
||||
AK4671_AD_DA_POWER_MANAGEMENT, 6, 0),
|
||||
SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback",
|
||||
AK4671_AD_DA_POWER_MANAGEMENT, 7, 0),
|
||||
|
||||
/* ADC */
|
||||
SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture",
|
||||
AK4671_AD_DA_POWER_MANAGEMENT, 4, 0),
|
||||
SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture",
|
||||
AK4671_AD_DA_POWER_MANAGEMENT, 5, 0),
|
||||
|
||||
/* PGA */
|
||||
SND_SOC_DAPM_PGA("LOUT2 Mix Amp",
|
||||
AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ROUT2 Mix Amp",
|
||||
AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("LIN1 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("RIN1 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("LIN2 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("RIN2 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("LIN3 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("RIN3 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("LIN4 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("RIN4 Mixing Circuit",
|
||||
AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0),
|
||||
|
||||
/* Output Mixers */
|
||||
SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0,
|
||||
&ak4671_lout1_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_lout1_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0,
|
||||
&ak4671_rout1_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_rout1_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
|
||||
0, 0, &ak4671_lout2_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_lout2_mixer_controls),
|
||||
ak4671_out2_event,
|
||||
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
|
||||
1, 0, &ak4671_rout2_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_rout2_mixer_controls),
|
||||
ak4671_out2_event,
|
||||
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0,
|
||||
&ak4671_lout3_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_lout3_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0,
|
||||
&ak4671_rout3_mixer_controls[0],
|
||||
ARRAY_SIZE(ak4671_rout3_mixer_controls)),
|
||||
|
||||
/* Input MUXs */
|
||||
SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0,
|
||||
&ak4671_lin_mux_control),
|
||||
SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0,
|
||||
&ak4671_rin_mux_control),
|
||||
|
||||
/* Mic Power */
|
||||
SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0),
|
||||
|
||||
/* Supply */
|
||||
SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4671_intercon[] = {
|
||||
{"DAC Left", NULL, "PMPLL"},
|
||||
{"DAC Right", NULL, "PMPLL"},
|
||||
{"ADC Left", NULL, "PMPLL"},
|
||||
{"ADC Right", NULL, "PMPLL"},
|
||||
|
||||
/* Outputs */
|
||||
{"LOUT1", NULL, "LOUT1 Mixer"},
|
||||
{"ROUT1", NULL, "ROUT1 Mixer"},
|
||||
{"LOUT2", NULL, "LOUT2 Mix Amp"},
|
||||
{"ROUT2", NULL, "ROUT2 Mix Amp"},
|
||||
{"LOUT3", NULL, "LOUT3 Mixer"},
|
||||
{"ROUT3", NULL, "ROUT3 Mixer"},
|
||||
|
||||
{"LOUT1 Mixer", "DACL", "DAC Left"},
|
||||
{"ROUT1 Mixer", "DACR", "DAC Right"},
|
||||
{"LOUT2 Mixer", "DACHL", "DAC Left"},
|
||||
{"ROUT2 Mixer", "DACHR", "DAC Right"},
|
||||
{"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
|
||||
{"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
|
||||
{"LOUT3 Mixer", "DACSL", "DAC Left"},
|
||||
{"ROUT3 Mixer", "DACSR", "DAC Right"},
|
||||
|
||||
/* Inputs */
|
||||
{"LIN MUX", "LIN1", "LIN1"},
|
||||
{"LIN MUX", "LIN2", "LIN2"},
|
||||
{"LIN MUX", "LIN3", "LIN3"},
|
||||
{"LIN MUX", "LIN4", "LIN4"},
|
||||
|
||||
{"RIN MUX", "RIN1", "RIN1"},
|
||||
{"RIN MUX", "RIN2", "RIN2"},
|
||||
{"RIN MUX", "RIN3", "RIN3"},
|
||||
{"RIN MUX", "RIN4", "RIN4"},
|
||||
|
||||
{"LIN1", NULL, "Mic Bias"},
|
||||
{"RIN1", NULL, "Mic Bias"},
|
||||
{"LIN2", NULL, "Mic Bias"},
|
||||
{"RIN2", NULL, "Mic Bias"},
|
||||
|
||||
{"ADC Left", NULL, "LIN MUX"},
|
||||
{"ADC Right", NULL, "RIN MUX"},
|
||||
|
||||
/* Analog Loops */
|
||||
{"LIN1 Mixing Circuit", NULL, "LIN1"},
|
||||
{"RIN1 Mixing Circuit", NULL, "RIN1"},
|
||||
{"LIN2 Mixing Circuit", NULL, "LIN2"},
|
||||
{"RIN2 Mixing Circuit", NULL, "RIN2"},
|
||||
{"LIN3 Mixing Circuit", NULL, "LIN3"},
|
||||
{"RIN3 Mixing Circuit", NULL, "RIN3"},
|
||||
{"LIN4 Mixing Circuit", NULL, "LIN4"},
|
||||
{"RIN4 Mixing Circuit", NULL, "RIN4"},
|
||||
|
||||
{"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
|
||||
{"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
|
||||
{"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"},
|
||||
{"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"},
|
||||
{"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"},
|
||||
{"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"},
|
||||
|
||||
{"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"},
|
||||
{"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"},
|
||||
{"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"},
|
||||
{"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"},
|
||||
{"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"},
|
||||
{"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"},
|
||||
|
||||
{"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"},
|
||||
{"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"},
|
||||
{"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"},
|
||||
{"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"},
|
||||
{"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"},
|
||||
{"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"},
|
||||
|
||||
{"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"},
|
||||
{"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"},
|
||||
{"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"},
|
||||
{"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"},
|
||||
{"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"},
|
||||
{"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
|
||||
};
|
||||
|
||||
static int ak4671_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 fs;
|
||||
|
||||
fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
|
||||
fs &= ~AK4671_FS;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 8000:
|
||||
fs |= AK4671_FS_8KHZ;
|
||||
break;
|
||||
case 12000:
|
||||
fs |= AK4671_FS_12KHZ;
|
||||
break;
|
||||
case 16000:
|
||||
fs |= AK4671_FS_16KHZ;
|
||||
break;
|
||||
case 24000:
|
||||
fs |= AK4671_FS_24KHZ;
|
||||
break;
|
||||
case 11025:
|
||||
fs |= AK4671_FS_11_025KHZ;
|
||||
break;
|
||||
case 22050:
|
||||
fs |= AK4671_FS_22_05KHZ;
|
||||
break;
|
||||
case 32000:
|
||||
fs |= AK4671_FS_32KHZ;
|
||||
break;
|
||||
case 44100:
|
||||
fs |= AK4671_FS_44_1KHZ;
|
||||
break;
|
||||
case 48000:
|
||||
fs |= AK4671_FS_48KHZ;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 pll;
|
||||
|
||||
pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
|
||||
pll &= ~AK4671_PLL;
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
pll |= AK4671_PLL_11_2896MHZ;
|
||||
break;
|
||||
case 12000000:
|
||||
pll |= AK4671_PLL_12MHZ;
|
||||
break;
|
||||
case 12288000:
|
||||
pll |= AK4671_PLL_12_288MHZ;
|
||||
break;
|
||||
case 13000000:
|
||||
pll |= AK4671_PLL_13MHZ;
|
||||
break;
|
||||
case 13500000:
|
||||
pll |= AK4671_PLL_13_5MHZ;
|
||||
break;
|
||||
case 19200000:
|
||||
pll |= AK4671_PLL_19_2MHZ;
|
||||
break;
|
||||
case 24000000:
|
||||
pll |= AK4671_PLL_24MHZ;
|
||||
break;
|
||||
case 26000000:
|
||||
pll |= AK4671_PLL_26MHZ;
|
||||
break;
|
||||
case 27000000:
|
||||
pll |= AK4671_PLL_27MHZ;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 mode;
|
||||
u8 format;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
mode |= AK4671_M_S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
mode &= ~(AK4671_M_S);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* interface format */
|
||||
format = snd_soc_read(codec, AK4671_FORMAT_SELECT);
|
||||
format &= ~AK4671_DIF;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
format |= AK4671_DIF_I2S_MODE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
format |= AK4671_DIF_MSB_MODE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
format |= AK4671_DIF_DSP_MODE;
|
||||
format |= AK4671_BCKP;
|
||||
format |= AK4671_MSBS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set mode and format */
|
||||
snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode);
|
||||
snd_soc_write(codec, AK4671_FORMAT_SELECT, format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4671_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, AK4671_AD_DA_POWER_MANAGEMENT,
|
||||
AK4671_PMVCM, AK4671_PMVCM);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
|
||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
||||
SNDRV_PCM_RATE_48000)
|
||||
|
||||
#define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
|
||||
static const struct snd_soc_dai_ops ak4671_dai_ops = {
|
||||
.hw_params = ak4671_hw_params,
|
||||
.set_sysclk = ak4671_set_dai_sysclk,
|
||||
.set_fmt = ak4671_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak4671_dai = {
|
||||
.name = "ak4671-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4671_RATES,
|
||||
.formats = AK4671_FORMATS,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = AK4671_RATES,
|
||||
.formats = AK4671_FORMATS,},
|
||||
.ops = &ak4671_dai_ops,
|
||||
};
|
||||
|
||||
static int ak4671_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
static int ak4671_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
|
||||
.probe = ak4671_probe,
|
||||
.remove = ak4671_remove,
|
||||
.set_bias_level = ak4671_set_bias_level,
|
||||
.controls = ak4671_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4671_snd_controls),
|
||||
.dapm_widgets = ak4671_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
|
||||
.dapm_routes = ak4671_intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4671_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = AK4671_SAR_ADC_CONTROL,
|
||||
.reg_defaults = ak4671_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int ak4671_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &ak4671_regmap);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_dev_ak4671, &ak4671_dai, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak4671_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak4671_i2c_id[] = {
|
||||
{ "ak4671", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
|
||||
|
||||
static struct i2c_driver ak4671_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4671-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ak4671_i2c_probe,
|
||||
.remove = ak4671_i2c_remove,
|
||||
.id_table = ak4671_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ak4671_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AK4671 codec driver");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
151
sound/soc/codecs/ak4671.h
Normal file
151
sound/soc/codecs/ak4671.h
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* ak4671.h -- audio driver for AK4671
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AK4671_H
|
||||
#define _AK4671_H
|
||||
|
||||
#define AK4671_AD_DA_POWER_MANAGEMENT 0x00
|
||||
#define AK4671_PLL_MODE_SELECT0 0x01
|
||||
#define AK4671_PLL_MODE_SELECT1 0x02
|
||||
#define AK4671_FORMAT_SELECT 0x03
|
||||
#define AK4671_MIC_SIGNAL_SELECT 0x04
|
||||
#define AK4671_MIC_AMP_GAIN 0x05
|
||||
#define AK4671_MIXING_POWER_MANAGEMENT0 0x06
|
||||
#define AK4671_MIXING_POWER_MANAGEMENT1 0x07
|
||||
#define AK4671_OUTPUT_VOLUME_CONTROL 0x08
|
||||
#define AK4671_LOUT1_SIGNAL_SELECT 0x09
|
||||
#define AK4671_ROUT1_SIGNAL_SELECT 0x0a
|
||||
#define AK4671_LOUT2_SIGNAL_SELECT 0x0b
|
||||
#define AK4671_ROUT2_SIGNAL_SELECT 0x0c
|
||||
#define AK4671_LOUT3_SIGNAL_SELECT 0x0d
|
||||
#define AK4671_ROUT3_SIGNAL_SELECT 0x0e
|
||||
#define AK4671_LOUT1_POWER_MANAGERMENT 0x0f
|
||||
#define AK4671_LOUT2_POWER_MANAGERMENT 0x10
|
||||
#define AK4671_LOUT3_POWER_MANAGERMENT 0x11
|
||||
#define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12
|
||||
#define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13
|
||||
#define AK4671_ALC_REFERENCE_SELECT 0x14
|
||||
#define AK4671_DIGITAL_MIXING_CONTROL 0x15
|
||||
#define AK4671_ALC_TIMER_SELECT 0x16
|
||||
#define AK4671_ALC_MODE_CONTROL 0x17
|
||||
#define AK4671_MODE_CONTROL1 0x18
|
||||
#define AK4671_MODE_CONTROL2 0x19
|
||||
#define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a
|
||||
#define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b
|
||||
#define AK4671_SIDETONE_A_CONTROL 0x1c
|
||||
#define AK4671_DIGITAL_FILTER_SELECT 0x1d
|
||||
#define AK4671_FIL3_COEFFICIENT0 0x1e
|
||||
#define AK4671_FIL3_COEFFICIENT1 0x1f
|
||||
#define AK4671_FIL3_COEFFICIENT2 0x20
|
||||
#define AK4671_FIL3_COEFFICIENT3 0x21
|
||||
#define AK4671_EQ_COEFFICIENT0 0x22
|
||||
#define AK4671_EQ_COEFFICIENT1 0x23
|
||||
#define AK4671_EQ_COEFFICIENT2 0x24
|
||||
#define AK4671_EQ_COEFFICIENT3 0x25
|
||||
#define AK4671_EQ_COEFFICIENT4 0x26
|
||||
#define AK4671_EQ_COEFFICIENT5 0x27
|
||||
#define AK4671_FIL1_COEFFICIENT0 0x28
|
||||
#define AK4671_FIL1_COEFFICIENT1 0x29
|
||||
#define AK4671_FIL1_COEFFICIENT2 0x2a
|
||||
#define AK4671_FIL1_COEFFICIENT3 0x2b
|
||||
#define AK4671_FIL2_COEFFICIENT0 0x2c
|
||||
#define AK4671_FIL2_COEFFICIENT1 0x2d
|
||||
#define AK4671_FIL2_COEFFICIENT2 0x2e
|
||||
#define AK4671_FIL2_COEFFICIENT3 0x2f
|
||||
#define AK4671_DIGITAL_FILTER_SELECT2 0x30
|
||||
#define AK4671_E1_COEFFICIENT0 0x32
|
||||
#define AK4671_E1_COEFFICIENT1 0x33
|
||||
#define AK4671_E1_COEFFICIENT2 0x34
|
||||
#define AK4671_E1_COEFFICIENT3 0x35
|
||||
#define AK4671_E1_COEFFICIENT4 0x36
|
||||
#define AK4671_E1_COEFFICIENT5 0x37
|
||||
#define AK4671_E2_COEFFICIENT0 0x38
|
||||
#define AK4671_E2_COEFFICIENT1 0x39
|
||||
#define AK4671_E2_COEFFICIENT2 0x3a
|
||||
#define AK4671_E2_COEFFICIENT3 0x3b
|
||||
#define AK4671_E2_COEFFICIENT4 0x3c
|
||||
#define AK4671_E2_COEFFICIENT5 0x3d
|
||||
#define AK4671_E3_COEFFICIENT0 0x3e
|
||||
#define AK4671_E3_COEFFICIENT1 0x3f
|
||||
#define AK4671_E3_COEFFICIENT2 0x40
|
||||
#define AK4671_E3_COEFFICIENT3 0x41
|
||||
#define AK4671_E3_COEFFICIENT4 0x42
|
||||
#define AK4671_E3_COEFFICIENT5 0x43
|
||||
#define AK4671_E4_COEFFICIENT0 0x44
|
||||
#define AK4671_E4_COEFFICIENT1 0x45
|
||||
#define AK4671_E4_COEFFICIENT2 0x46
|
||||
#define AK4671_E4_COEFFICIENT3 0x47
|
||||
#define AK4671_E4_COEFFICIENT4 0x48
|
||||
#define AK4671_E4_COEFFICIENT5 0x49
|
||||
#define AK4671_E5_COEFFICIENT0 0x4a
|
||||
#define AK4671_E5_COEFFICIENT1 0x4b
|
||||
#define AK4671_E5_COEFFICIENT2 0x4c
|
||||
#define AK4671_E5_COEFFICIENT3 0x4d
|
||||
#define AK4671_E5_COEFFICIENT4 0x4e
|
||||
#define AK4671_E5_COEFFICIENT5 0x4f
|
||||
#define AK4671_EQ_CONTROL_250HZ_100HZ 0x50
|
||||
#define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51
|
||||
#define AK4671_EQ_CONTRO_10KHZ 0x52
|
||||
#define AK4671_PCM_IF_CONTROL0 0x53
|
||||
#define AK4671_PCM_IF_CONTROL1 0x54
|
||||
#define AK4671_PCM_IF_CONTROL2 0x55
|
||||
#define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56
|
||||
#define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57
|
||||
#define AK4671_SIDETONE_VOLUME_CONTROL 0x58
|
||||
#define AK4671_DIGITAL_MIXING_CONTROL2 0x59
|
||||
#define AK4671_SAR_ADC_CONTROL 0x5a
|
||||
|
||||
/* Bitfield Definitions */
|
||||
|
||||
/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
|
||||
#define AK4671_PMVCM 0x01
|
||||
|
||||
/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */
|
||||
#define AK4671_PLL 0x0f
|
||||
#define AK4671_PLL_11_2896MHZ (4 << 0)
|
||||
#define AK4671_PLL_12_288MHZ (5 << 0)
|
||||
#define AK4671_PLL_12MHZ (6 << 0)
|
||||
#define AK4671_PLL_24MHZ (7 << 0)
|
||||
#define AK4671_PLL_19_2MHZ (8 << 0)
|
||||
#define AK4671_PLL_13_5MHZ (12 << 0)
|
||||
#define AK4671_PLL_27MHZ (13 << 0)
|
||||
#define AK4671_PLL_13MHZ (14 << 0)
|
||||
#define AK4671_PLL_26MHZ (15 << 0)
|
||||
#define AK4671_FS 0xf0
|
||||
#define AK4671_FS_8KHZ (0 << 4)
|
||||
#define AK4671_FS_12KHZ (1 << 4)
|
||||
#define AK4671_FS_16KHZ (2 << 4)
|
||||
#define AK4671_FS_24KHZ (3 << 4)
|
||||
#define AK4671_FS_11_025KHZ (5 << 4)
|
||||
#define AK4671_FS_22_05KHZ (7 << 4)
|
||||
#define AK4671_FS_32KHZ (10 << 4)
|
||||
#define AK4671_FS_48KHZ (11 << 4)
|
||||
#define AK4671_FS_44_1KHZ (15 << 4)
|
||||
|
||||
/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */
|
||||
#define AK4671_PMPLL 0x01
|
||||
#define AK4671_M_S 0x02
|
||||
|
||||
/* AK4671_FORMAT_SELECT (0x03) Fields */
|
||||
#define AK4671_DIF 0x03
|
||||
#define AK4671_DIF_DSP_MODE (0 << 0)
|
||||
#define AK4671_DIF_MSB_MODE (2 << 0)
|
||||
#define AK4671_DIF_I2S_MODE (3 << 0)
|
||||
#define AK4671_BCKP 0x04
|
||||
#define AK4671_MSBS 0x08
|
||||
#define AK4671_SDOD 0x10
|
||||
|
||||
/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
|
||||
#define AK4671_MUTEN 0x04
|
||||
|
||||
#endif
|
||||
217
sound/soc/codecs/ak5386.c
Normal file
217
sound/soc/codecs/ak5386.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* ALSA SoC driver for
|
||||
* Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
|
||||
*
|
||||
* (c) 2013 Daniel Mack <zonque@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
static const char * const supply_names[] = {
|
||||
"va", "vd"
|
||||
};
|
||||
|
||||
struct ak5386_priv {
|
||||
int reset_gpio;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("AINL"),
|
||||
SND_SOC_DAPM_INPUT("AINR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
|
||||
{ "Capture", NULL, "AINL" },
|
||||
{ "Capture", NULL, "AINR" },
|
||||
};
|
||||
|
||||
static int ak5386_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
}
|
||||
|
||||
static int ak5386_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ak5386_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak5386_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
}
|
||||
#else
|
||||
#define ak5386_soc_suspend NULL
|
||||
#define ak5386_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_ak5386 = {
|
||||
.probe = ak5386_soc_probe,
|
||||
.remove = ak5386_soc_remove,
|
||||
.suspend = ak5386_soc_suspend,
|
||||
.resume = ak5386_soc_resume,
|
||||
.dapm_widgets = ak5386_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
|
||||
.dapm_routes = ak5386_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
|
||||
};
|
||||
|
||||
static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
|
||||
format &= SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
if (format != SND_SOC_DAIFMT_LEFT_J &&
|
||||
format != SND_SOC_DAIFMT_I2S) {
|
||||
dev_err(codec->dev, "Invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak5386_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/*
|
||||
* From the datasheet:
|
||||
*
|
||||
* All external clocks (MCLK, SCLK and LRCK) must be present unless
|
||||
* PDN pin = “L”. If these clocks are not provided, the AK5386 may
|
||||
* draw excess current due to its use of internal dynamically
|
||||
* refreshed logic. If the external clocks are not present, place
|
||||
* the AK5386 in power-down mode (PDN pin = “L”).
|
||||
*/
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
gpio_set_value(priv->reset_gpio, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak5386_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
gpio_set_value(priv->reset_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak5386_dai_ops = {
|
||||
.set_fmt = ak5386_set_dai_fmt,
|
||||
.hw_params = ak5386_hw_params,
|
||||
.hw_free = ak5386_hw_free,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak5386_dai = {
|
||||
.name = "ak5386-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
},
|
||||
.ops = &ak5386_dai_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ak5386_dt_ids[] = {
|
||||
{ .compatible = "asahi-kasei,ak5386", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
|
||||
#endif
|
||||
|
||||
static int ak5386_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ak5386_priv *priv;
|
||||
int ret, i;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reset_gpio = -EINVAL;
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
priv->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
|
||||
priv->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
|
||||
priv->reset_gpio = of_get_named_gpio(dev->of_node,
|
||||
"reset-gpio", 0);
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
if (devm_gpio_request_one(dev, priv->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"AK5386 Reset"))
|
||||
priv->reset_gpio = -EINVAL;
|
||||
|
||||
return snd_soc_register_codec(dev, &soc_codec_ak5386,
|
||||
&ak5386_dai, 1);
|
||||
}
|
||||
|
||||
static int ak5386_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ak5386_driver = {
|
||||
.probe = ak5386_probe,
|
||||
.remove = ak5386_remove,
|
||||
.driver = {
|
||||
.name = "ak5386",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ak5386_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ak5386_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
|
||||
MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
1119
sound/soc/codecs/alc5623.c
Normal file
1119
sound/soc/codecs/alc5623.c
Normal file
File diff suppressed because it is too large
Load diff
161
sound/soc/codecs/alc5623.h
Normal file
161
sound/soc/codecs/alc5623.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* alc5623.h -- alc562[123] ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright 2008 Realtek Microelectronics
|
||||
* Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
*
|
||||
* Author: flove <flove@realtek.com>
|
||||
* Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ALC5623_H
|
||||
#define _ALC5623_H
|
||||
|
||||
#define ALC5623_RESET 0x00
|
||||
/* 5621 5622 5623 */
|
||||
/* speaker output vol 2 2 */
|
||||
/* line output vol 4 2 */
|
||||
/* HP output vol 4 0 4 */
|
||||
#define ALC5623_SPK_OUT_VOL 0x02
|
||||
#define ALC5623_HP_OUT_VOL 0x04
|
||||
#define ALC5623_MONO_AUX_OUT_VOL 0x06
|
||||
#define ALC5623_AUXIN_VOL 0x08
|
||||
#define ALC5623_LINE_IN_VOL 0x0A
|
||||
#define ALC5623_STEREO_DAC_VOL 0x0C
|
||||
#define ALC5623_MIC_VOL 0x0E
|
||||
#define ALC5623_MIC_ROUTING_CTRL 0x10
|
||||
#define ALC5623_ADC_REC_GAIN 0x12
|
||||
#define ALC5623_ADC_REC_MIXER 0x14
|
||||
#define ALC5623_SOFT_VOL_CTRL_TIME 0x16
|
||||
/* ALC5623_OUTPUT_MIXER_CTRL : */
|
||||
/* same remark as for reg 2 line vs speaker */
|
||||
#define ALC5623_OUTPUT_MIXER_CTRL 0x1C
|
||||
#define ALC5623_MIC_CTRL 0x22
|
||||
|
||||
#define ALC5623_DAI_CONTROL 0x34
|
||||
#define ALC5623_DAI_SDP_MASTER_MODE (0 << 15)
|
||||
#define ALC5623_DAI_SDP_SLAVE_MODE (1 << 15)
|
||||
#define ALC5623_DAI_I2S_PCM_MODE (1 << 14)
|
||||
#define ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL (1 << 7)
|
||||
#define ALC5623_DAI_ADC_DATA_L_R_SWAP (1 << 5)
|
||||
#define ALC5623_DAI_DAC_DATA_L_R_SWAP (1 << 4)
|
||||
#define ALC5623_DAI_I2S_DL_MASK (3 << 2)
|
||||
#define ALC5623_DAI_I2S_DL_32 (3 << 2)
|
||||
#define ALC5623_DAI_I2S_DL_24 (2 << 2)
|
||||
#define ALC5623_DAI_I2S_DL_20 (1 << 2)
|
||||
#define ALC5623_DAI_I2S_DL_16 (0 << 2)
|
||||
#define ALC5623_DAI_I2S_DF_PCM (3 << 0)
|
||||
#define ALC5623_DAI_I2S_DF_LEFT (2 << 0)
|
||||
#define ALC5623_DAI_I2S_DF_RIGHT (1 << 0)
|
||||
#define ALC5623_DAI_I2S_DF_I2S (0 << 0)
|
||||
|
||||
#define ALC5623_STEREO_AD_DA_CLK_CTRL 0x36
|
||||
#define ALC5623_COMPANDING_CTRL 0x38
|
||||
|
||||
#define ALC5623_PWR_MANAG_ADD1 0x3A
|
||||
#define ALC5623_PWR_ADD1_MAIN_I2S_EN (1 << 15)
|
||||
#define ALC5623_PWR_ADD1_ZC_DET_PD_EN (1 << 14)
|
||||
#define ALC5623_PWR_ADD1_MIC1_BIAS_EN (1 << 11)
|
||||
#define ALC5623_PWR_ADD1_SHORT_CURR_DET_EN (1 << 10)
|
||||
#define ALC5623_PWR_ADD1_SOFTGEN_EN (1 << 8) /* rsvd on 5622 */
|
||||
#define ALC5623_PWR_ADD1_DEPOP_BUF_HP (1 << 6) /* rsvd on 5622 */
|
||||
#define ALC5623_PWR_ADD1_HP_OUT_AMP (1 << 5)
|
||||
#define ALC5623_PWR_ADD1_HP_OUT_ENH_AMP (1 << 4) /* rsvd on 5622 */
|
||||
#define ALC5623_PWR_ADD1_DEPOP_BUF_AUX (1 << 2)
|
||||
#define ALC5623_PWR_ADD1_AUX_OUT_AMP (1 << 1)
|
||||
#define ALC5623_PWR_ADD1_AUX_OUT_ENH_AMP (1 << 0) /* rsvd on 5622 */
|
||||
|
||||
#define ALC5623_PWR_MANAG_ADD2 0x3C
|
||||
#define ALC5623_PWR_ADD2_LINEOUT (1 << 15) /* rt5623 */
|
||||
#define ALC5623_PWR_ADD2_CLASS_AB (1 << 15) /* rt5621 */
|
||||
#define ALC5623_PWR_ADD2_CLASS_D (1 << 14) /* rt5621 */
|
||||
#define ALC5623_PWR_ADD2_VREF (1 << 13)
|
||||
#define ALC5623_PWR_ADD2_PLL (1 << 12)
|
||||
#define ALC5623_PWR_ADD2_DAC_REF_CIR (1 << 10)
|
||||
#define ALC5623_PWR_ADD2_L_DAC_CLK (1 << 9)
|
||||
#define ALC5623_PWR_ADD2_R_DAC_CLK (1 << 8)
|
||||
#define ALC5623_PWR_ADD2_L_ADC_CLK_GAIN (1 << 7)
|
||||
#define ALC5623_PWR_ADD2_R_ADC_CLK_GAIN (1 << 6)
|
||||
#define ALC5623_PWR_ADD2_L_HP_MIXER (1 << 5)
|
||||
#define ALC5623_PWR_ADD2_R_HP_MIXER (1 << 4)
|
||||
#define ALC5623_PWR_ADD2_SPK_MIXER (1 << 3)
|
||||
#define ALC5623_PWR_ADD2_MONO_MIXER (1 << 2)
|
||||
#define ALC5623_PWR_ADD2_L_ADC_REC_MIXER (1 << 1)
|
||||
#define ALC5623_PWR_ADD2_R_ADC_REC_MIXER (1 << 0)
|
||||
|
||||
#define ALC5623_PWR_MANAG_ADD3 0x3E
|
||||
#define ALC5623_PWR_ADD3_MAIN_BIAS (1 << 15)
|
||||
#define ALC5623_PWR_ADD3_AUXOUT_L_VOL_AMP (1 << 14)
|
||||
#define ALC5623_PWR_ADD3_AUXOUT_R_VOL_AMP (1 << 13)
|
||||
#define ALC5623_PWR_ADD3_SPK_OUT (1 << 12)
|
||||
#define ALC5623_PWR_ADD3_HP_L_OUT_VOL (1 << 10)
|
||||
#define ALC5623_PWR_ADD3_HP_R_OUT_VOL (1 << 9)
|
||||
#define ALC5623_PWR_ADD3_LINEIN_L_VOL (1 << 7)
|
||||
#define ALC5623_PWR_ADD3_LINEIN_R_VOL (1 << 6)
|
||||
#define ALC5623_PWR_ADD3_AUXIN_L_VOL (1 << 5)
|
||||
#define ALC5623_PWR_ADD3_AUXIN_R_VOL (1 << 4)
|
||||
#define ALC5623_PWR_ADD3_MIC1_FUN_CTRL (1 << 3)
|
||||
#define ALC5623_PWR_ADD3_MIC2_FUN_CTRL (1 << 2)
|
||||
#define ALC5623_PWR_ADD3_MIC1_BOOST_AD (1 << 1)
|
||||
#define ALC5623_PWR_ADD3_MIC2_BOOST_AD (1 << 0)
|
||||
|
||||
#define ALC5623_ADD_CTRL_REG 0x40
|
||||
|
||||
#define ALC5623_GLOBAL_CLK_CTRL_REG 0x42
|
||||
#define ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL (1 << 15)
|
||||
#define ALC5623_GBL_CLK_SYS_SOUR_SEL_MCLK (0 << 15)
|
||||
#define ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK (1 << 14)
|
||||
#define ALC5623_GBL_CLK_PLL_SOUR_SEL_MCLK (0 << 14)
|
||||
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV8 (3 << 1)
|
||||
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV4 (2 << 1)
|
||||
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV2 (1 << 1)
|
||||
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV1 (0 << 1)
|
||||
#define ALC5623_GBL_CLK_PLL_PRE_DIV2 (1 << 0)
|
||||
#define ALC5623_GBL_CLK_PLL_PRE_DIV1 (0 << 0)
|
||||
|
||||
#define ALC5623_PLL_CTRL 0x44
|
||||
#define ALC5623_PLL_CTRL_N_VAL(n) (((n)&0xff) << 8)
|
||||
#define ALC5623_PLL_CTRL_K_VAL(k) (((k)&0x7) << 4)
|
||||
#define ALC5623_PLL_CTRL_M_VAL(m) ((m)&0xf)
|
||||
|
||||
#define ALC5623_GPIO_OUTPUT_PIN_CTRL 0x4A
|
||||
#define ALC5623_GPIO_PIN_CONFIG 0x4C
|
||||
#define ALC5623_GPIO_PIN_POLARITY 0x4E
|
||||
#define ALC5623_GPIO_PIN_STICKY 0x50
|
||||
#define ALC5623_GPIO_PIN_WAKEUP 0x52
|
||||
#define ALC5623_GPIO_PIN_STATUS 0x54
|
||||
#define ALC5623_GPIO_PIN_SHARING 0x56
|
||||
#define ALC5623_OVER_CURR_STATUS 0x58
|
||||
#define ALC5623_JACK_DET_CTRL 0x5A
|
||||
|
||||
#define ALC5623_MISC_CTRL 0x5E
|
||||
#define ALC5623_MISC_DISABLE_FAST_VREG (1 << 15)
|
||||
#define ALC5623_MISC_SPK_CLASS_AB_OC_PD (1 << 13) /* 5621 */
|
||||
#define ALC5623_MISC_SPK_CLASS_AB_OC_DET (1 << 12) /* 5621 */
|
||||
#define ALC5623_MISC_HP_DEPOP_MODE3_EN (1 << 10)
|
||||
#define ALC5623_MISC_HP_DEPOP_MODE2_EN (1 << 9)
|
||||
#define ALC5623_MISC_HP_DEPOP_MODE1_EN (1 << 8)
|
||||
#define ALC5623_MISC_AUXOUT_DEPOP_MODE3_EN (1 << 6)
|
||||
#define ALC5623_MISC_AUXOUT_DEPOP_MODE2_EN (1 << 5)
|
||||
#define ALC5623_MISC_AUXOUT_DEPOP_MODE1_EN (1 << 4)
|
||||
#define ALC5623_MISC_M_DAC_L_INPUT (1 << 3)
|
||||
#define ALC5623_MISC_M_DAC_R_INPUT (1 << 2)
|
||||
#define ALC5623_MISC_IRQOUT_INV_CTRL (1 << 0)
|
||||
|
||||
#define ALC5623_PSEDUEO_SPATIAL_CTRL 0x60
|
||||
#define ALC5623_EQ_CTRL 0x62
|
||||
#define ALC5623_EQ_MODE_ENABLE 0x66
|
||||
#define ALC5623_AVC_CTRL 0x68
|
||||
#define ALC5623_HID_CTRL_INDEX 0x6A
|
||||
#define ALC5623_HID_CTRL_DATA 0x6C
|
||||
#define ALC5623_VENDOR_ID1 0x7C
|
||||
#define ALC5623_VENDOR_ID2 0x7E
|
||||
|
||||
#define ALC5623_PLL_FR_MCLK 0
|
||||
#define ALC5623_PLL_FR_BCK 1
|
||||
#endif
|
||||
1215
sound/soc/codecs/alc5632.c
Normal file
1215
sound/soc/codecs/alc5632.c
Normal file
File diff suppressed because it is too large
Load diff
252
sound/soc/codecs/alc5632.h
Normal file
252
sound/soc/codecs/alc5632.h
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* alc5632.h -- ALC5632 ALSA SoC Audio Codec
|
||||
*
|
||||
* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
|
||||
*
|
||||
* Authors: Leon Romanovsky <leon@leon.nu>
|
||||
* Andrey Danin <danindrey@mail.ru>
|
||||
* Ilya Petrov <ilya.muromec@gmail.com>
|
||||
* Marc Dietrich <marvin24@gmx.de>
|
||||
*
|
||||
* Based on alc5623.h by Arnaud Patard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ALC5632_H
|
||||
#define _ALC5632_H
|
||||
|
||||
#define ALC5632_RESET 0x00
|
||||
/* speaker output vol 2 2 */
|
||||
/* line output vol 4 2 */
|
||||
/* HP output vol 4 0 4 */
|
||||
#define ALC5632_SPK_OUT_VOL 0x02 /* spe out vol */
|
||||
#define ALC5632_SPK_OUT_VOL_STEP 1.5
|
||||
#define ALC5632_HP_OUT_VOL 0x04 /* hp out vol */
|
||||
#define ALC5632_AUX_OUT_VOL 0x06 /* aux out vol */
|
||||
#define ALC5632_PHONE_IN_VOL 0x08 /* phone in vol */
|
||||
#define ALC5632_LINE_IN_VOL 0x0A /* line in vol */
|
||||
#define ALC5632_STEREO_DAC_IN_VOL 0x0C /* stereo dac in vol */
|
||||
#define ALC5632_MIC_VOL 0x0E /* mic in vol */
|
||||
/* stero dac/mic routing */
|
||||
#define ALC5632_MIC_ROUTING_CTRL 0x10
|
||||
#define ALC5632_MIC_ROUTE_MONOMIX (1 << 0)
|
||||
#define ALC5632_MIC_ROUTE_SPK (1 << 1)
|
||||
#define ALC5632_MIC_ROUTE_HP (1 << 2)
|
||||
|
||||
#define ALC5632_ADC_REC_GAIN 0x12 /* rec gain */
|
||||
#define ALC5632_ADC_REC_GAIN_RANGE 0x1F1F
|
||||
#define ALC5632_ADC_REC_GAIN_BASE (-16.5)
|
||||
#define ALC5632_ADC_REC_GAIN_STEP 1.5
|
||||
|
||||
#define ALC5632_ADC_REC_MIXER 0x14 /* mixer control */
|
||||
#define ALC5632_ADC_REC_MIC1 (1 << 6)
|
||||
#define ALC5632_ADC_REC_MIC2 (1 << 5)
|
||||
#define ALC5632_ADC_REC_LINE_IN (1 << 4)
|
||||
#define ALC5632_ADC_REC_AUX (1 << 3)
|
||||
#define ALC5632_ADC_REC_HP (1 << 2)
|
||||
#define ALC5632_ADC_REC_SPK (1 << 1)
|
||||
#define ALC5632_ADC_REC_MONOMIX (1 << 0)
|
||||
|
||||
#define ALC5632_VOICE_DAC_VOL 0x18 /* voice dac vol */
|
||||
#define ALC5632_I2S_OUT_CTL 0x1A /* undocumented reg. found in path scheme */
|
||||
/* ALC5632_OUTPUT_MIXER_CTRL : */
|
||||
/* same remark as for reg 2 line vs speaker */
|
||||
#define ALC5632_OUTPUT_MIXER_CTRL 0x1C /* out mix ctrl */
|
||||
#define ALC5632_OUTPUT_MIXER_RP (1 << 14)
|
||||
#define ALC5632_OUTPUT_MIXER_WEEK (1 << 12)
|
||||
#define ALC5632_OUTPUT_MIXER_HP (1 << 10)
|
||||
#define ALC5632_OUTPUT_MIXER_AUX_SPK (2 << 6)
|
||||
#define ALC5632_OUTPUT_MIXER_AUX_HP_LR (1 << 6)
|
||||
#define ALC5632_OUTPUT_MIXER_HP_R (1 << 8)
|
||||
#define ALC5632_OUTPUT_MIXER_HP_L (1 << 9)
|
||||
|
||||
#define ALC5632_MIC_CTRL 0x22 /* mic phone ctrl */
|
||||
#define ALC5632_MIC_BOOST_BYPASS 0
|
||||
#define ALC5632_MIC_BOOST_20DB 1
|
||||
#define ALC5632_MIC_BOOST_30DB 2
|
||||
#define ALC5632_MIC_BOOST_40DB 3
|
||||
|
||||
#define ALC5632_DIGI_BOOST_CTRL 0x24 /* digi mic / bost ctl */
|
||||
#define ALC5632_MIC_BOOST_RANGE 7
|
||||
#define ALC5632_MIC_BOOST_STEP 6
|
||||
#define ALC5632_PWR_DOWN_CTRL_STATUS 0x26
|
||||
#define ALC5632_PWR_DOWN_CTRL_STATUS_MASK 0xEF00
|
||||
#define ALC5632_PWR_VREF_PR3 (1 << 11)
|
||||
#define ALC5632_PWR_VREF_PR2 (1 << 10)
|
||||
#define ALC5632_PWR_VREF_STATUS (1 << 3)
|
||||
#define ALC5632_PWR_AMIX_STATUS (1 << 2)
|
||||
#define ALC5632_PWR_DAC_STATUS (1 << 1)
|
||||
#define ALC5632_PWR_ADC_STATUS (1 << 0)
|
||||
/* stereo/voice DAC / stereo adc func ctrl */
|
||||
#define ALC5632_DAC_FUNC_SELECT 0x2E
|
||||
|
||||
/* Main serial data port ctrl (i2s) */
|
||||
#define ALC5632_DAI_CONTROL 0x34
|
||||
|
||||
#define ALC5632_DAI_SDP_MASTER_MODE (0 << 15)
|
||||
#define ALC5632_DAI_SDP_SLAVE_MODE (1 << 15)
|
||||
#define ALC5632_DAI_SADLRCK_MODE (1 << 14)
|
||||
/* 0:voice, 1:main */
|
||||
#define ALC5632_DAI_MAIN_I2S_SYSCLK_SEL (1 << 8)
|
||||
#define ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL (1 << 7)
|
||||
/* 0:normal, 1:invert */
|
||||
#define ALC5632_DAI_MAIN_I2S_LRCK_INV (1 << 6)
|
||||
#define ALC5632_DAI_I2S_DL_MASK (3 << 2)
|
||||
#define ALC5632_DAI_I2S_DL_8 (3 << 2)
|
||||
#define ALC5632_DAI_I2S_DL_24 (2 << 2)
|
||||
#define ALC5632_DAI_I2S_DL_20 (1 << 2)
|
||||
#define ALC5632_DAI_I2S_DL_16 (0 << 2)
|
||||
#define ALC5632_DAI_I2S_DF_MASK (3 << 0)
|
||||
#define ALC5632_DAI_I2S_DF_PCM_B (3 << 0)
|
||||
#define ALC5632_DAI_I2S_DF_PCM_A (2 << 0)
|
||||
#define ALC5632_DAI_I2S_DF_LEFT (1 << 0)
|
||||
#define ALC5632_DAI_I2S_DF_I2S (0 << 0)
|
||||
/* extend serial data port control (VoDAC_i2c/pcm) */
|
||||
#define ALC5632_DAI_CONTROL2 0x36
|
||||
/* 0:gpio func, 1:voice pcm */
|
||||
#define ALC5632_DAI_VOICE_PCM_ENABLE (1 << 15)
|
||||
/* 0:master, 1:slave */
|
||||
#define ALC5632_DAI_VOICE_MODE_SEL (1 << 14)
|
||||
/* 0:disable, 1:enable */
|
||||
#define ALC5632_DAI_HPF_CLK_CTRL (1 << 13)
|
||||
/* 0:main, 1:voice */
|
||||
#define ALC5632_DAI_VOICE_I2S_SYSCLK_SEL (1 << 8)
|
||||
/* 0:normal, 1:invert */
|
||||
#define ALC5632_DAI_VOICE_VBCLK_SYSCLK_SEL (1 << 7)
|
||||
/* 0:normal, 1:invert */
|
||||
#define ALC5632_DAI_VOICE_I2S_LR_INV (1 << 6)
|
||||
#define ALC5632_DAI_VOICE_DL_MASK (3 << 2)
|
||||
#define ALC5632_DAI_VOICE_DL_16 (0 << 2)
|
||||
#define ALC5632_DAI_VOICE_DL_20 (1 << 2)
|
||||
#define ALC5632_DAI_VOICE_DL_24 (2 << 2)
|
||||
#define ALC5632_DAI_VOICE_DL_8 (3 << 2)
|
||||
#define ALC5632_DAI_VOICE_DF_MASK (3 << 0)
|
||||
#define ALC5632_DAI_VOICE_DF_I2S (0 << 0)
|
||||
#define ALC5632_DAI_VOICE_DF_LEFT (1 << 0)
|
||||
#define ALC5632_DAI_VOICE_DF_PCM_A (2 << 0)
|
||||
#define ALC5632_DAI_VOICE_DF_PCM_B (3 << 0)
|
||||
|
||||
#define ALC5632_PWR_MANAG_ADD1 0x3A
|
||||
#define ALC5632_PWR_MANAG_ADD1_MASK 0xEFFF
|
||||
#define ALC5632_PWR_ADD1_DAC_L_EN (1 << 15)
|
||||
#define ALC5632_PWR_ADD1_DAC_R_EN (1 << 14)
|
||||
#define ALC5632_PWR_ADD1_ZERO_CROSS (1 << 13)
|
||||
#define ALC5632_PWR_ADD1_MAIN_I2S_EN (1 << 11)
|
||||
#define ALC5632_PWR_ADD1_SPK_AMP_EN (1 << 10)
|
||||
#define ALC5632_PWR_ADD1_HP_OUT_AMP (1 << 9)
|
||||
#define ALC5632_PWR_ADD1_HP_OUT_ENH_AMP (1 << 8)
|
||||
#define ALC5632_PWR_ADD1_VOICE_DAC_MIX (1 << 7)
|
||||
#define ALC5632_PWR_ADD1_SOFTGEN_EN (1 << 6)
|
||||
#define ALC5632_PWR_ADD1_MIC1_SHORT_CURR (1 << 5)
|
||||
#define ALC5632_PWR_ADD1_MIC2_SHORT_CURR (1 << 4)
|
||||
#define ALC5632_PWR_ADD1_MIC1_EN (1 << 3)
|
||||
#define ALC5632_PWR_ADD1_MIC2_EN (1 << 2)
|
||||
#define ALC5632_PWR_ADD1_MAIN_BIAS (1 << 1)
|
||||
#define ALC5632_PWR_ADD1_DAC_REF (1 << 0)
|
||||
|
||||
#define ALC5632_PWR_MANAG_ADD2 0x3C
|
||||
#define ALC5632_PWR_MANAG_ADD2_MASK 0x7FFF
|
||||
#define ALC5632_PWR_ADD2_PLL1 (1 << 15)
|
||||
#define ALC5632_PWR_ADD2_PLL2 (1 << 14)
|
||||
#define ALC5632_PWR_ADD2_VREF (1 << 13)
|
||||
#define ALC5632_PWR_ADD2_OVT_DET (1 << 12)
|
||||
#define ALC5632_PWR_ADD2_VOICE_DAC (1 << 10)
|
||||
#define ALC5632_PWR_ADD2_L_DAC_CLK (1 << 9)
|
||||
#define ALC5632_PWR_ADD2_R_DAC_CLK (1 << 8)
|
||||
#define ALC5632_PWR_ADD2_L_ADC_CLK_GAIN (1 << 7)
|
||||
#define ALC5632_PWR_ADD2_R_ADC_CLK_GAIN (1 << 6)
|
||||
#define ALC5632_PWR_ADD2_L_HP_MIXER (1 << 5)
|
||||
#define ALC5632_PWR_ADD2_R_HP_MIXER (1 << 4)
|
||||
#define ALC5632_PWR_ADD2_SPK_MIXER (1 << 3)
|
||||
#define ALC5632_PWR_ADD2_MONO_MIXER (1 << 2)
|
||||
#define ALC5632_PWR_ADD2_L_ADC_REC_MIXER (1 << 1)
|
||||
#define ALC5632_PWR_ADD2_R_ADC_REC_MIXER (1 << 0)
|
||||
|
||||
#define ALC5632_PWR_MANAG_ADD3 0x3E
|
||||
#define ALC5632_PWR_MANAG_ADD3_MASK 0x7CFF
|
||||
#define ALC5632_PWR_ADD3_AUXOUT_VOL (1 << 14)
|
||||
#define ALC5632_PWR_ADD3_SPK_L_OUT (1 << 13)
|
||||
#define ALC5632_PWR_ADD3_SPK_R_OUT (1 << 12)
|
||||
#define ALC5632_PWR_ADD3_HP_L_OUT_VOL (1 << 11)
|
||||
#define ALC5632_PWR_ADD3_HP_R_OUT_VOL (1 << 10)
|
||||
#define ALC5632_PWR_ADD3_LINEIN_L_VOL (1 << 7)
|
||||
#define ALC5632_PWR_ADD3_LINEIN_R_VOL (1 << 6)
|
||||
#define ALC5632_PWR_ADD3_AUXIN_VOL (1 << 5)
|
||||
#define ALC5632_PWR_ADD3_AUXIN_MIX (1 << 4)
|
||||
#define ALC5632_PWR_ADD3_MIC1_VOL (1 << 3)
|
||||
#define ALC5632_PWR_ADD3_MIC2_VOL (1 << 2)
|
||||
#define ALC5632_PWR_ADD3_MIC1_BOOST_AD (1 << 1)
|
||||
#define ALC5632_PWR_ADD3_MIC2_BOOST_AD (1 << 0)
|
||||
|
||||
#define ALC5632_GPCR1 0x40
|
||||
#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1 (1 << 15)
|
||||
#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_MCLK (0 << 15)
|
||||
#define ALC5632_GPCR1_DAC_HI_FLT_EN (1 << 10)
|
||||
#define ALC5632_GPCR1_SPK_AMP_CTRL (7 << 1)
|
||||
#define ALC5632_GPCR1_VDD_100 (5 << 1)
|
||||
#define ALC5632_GPCR1_VDD_125 (4 << 1)
|
||||
#define ALC5632_GPCR1_VDD_150 (3 << 1)
|
||||
#define ALC5632_GPCR1_VDD_175 (2 << 1)
|
||||
#define ALC5632_GPCR1_VDD_200 (1 << 1)
|
||||
#define ALC5632_GPCR1_VDD_225 (0 << 1)
|
||||
|
||||
#define ALC5632_GPCR2 0x42
|
||||
#define ALC5632_GPCR2_PLL1_SOUR_SEL (3 << 12)
|
||||
#define ALC5632_PLL_FR_MCLK (0 << 12)
|
||||
#define ALC5632_PLL_FR_BCLK (2 << 12)
|
||||
#define ALC5632_PLL_FR_VBCLK (3 << 12)
|
||||
#define ALC5632_GPCR2_CLK_PLL_PRE_DIV1 (0 << 0)
|
||||
|
||||
#define ALC5632_PLL1_CTRL 0x44
|
||||
#define ALC5632_PLL1_CTRL_N_VAL(n) (((n) & 0x0f) << 8)
|
||||
#define ALC5632_PLL1_M_BYPASS (1 << 7)
|
||||
#define ALC5632_PLL1_CTRL_K_VAL(k) (((k) & 0x07) << 4)
|
||||
#define ALC5632_PLL1_CTRL_M_VAL(m) (((m) & 0x0f) << 0)
|
||||
|
||||
#define ALC5632_PLL2_CTRL 0x46
|
||||
#define ALC5632_PLL2_EN (1 << 15)
|
||||
#define ALC5632_PLL2_RATIO (0 << 15)
|
||||
|
||||
#define ALC5632_GPIO_PIN_CONFIG 0x4C
|
||||
#define ALC5632_GPIO_PIN_POLARITY 0x4E
|
||||
#define ALC5632_GPIO_PIN_STICKY 0x50
|
||||
#define ALC5632_GPIO_PIN_WAKEUP 0x52
|
||||
#define ALC5632_GPIO_PIN_STATUS 0x54
|
||||
#define ALC5632_GPIO_PIN_SHARING 0x56
|
||||
#define ALC5632_OVER_CURR_STATUS 0x58
|
||||
#define ALC5632_SOFTVOL_CTRL 0x5A
|
||||
#define ALC5632_GPIO_OUPUT_PIN_CTRL 0x5C
|
||||
|
||||
#define ALC5632_MISC_CTRL 0x5E
|
||||
#define ALC5632_MISC_DISABLE_FAST_VREG (1 << 15)
|
||||
#define ALC5632_MISC_AVC_TRGT_SEL (3 << 12)
|
||||
#define ALC5632_MISC_AVC_TRGT_RIGHT (1 << 12)
|
||||
#define ALC5632_MISC_AVC_TRGT_LEFT (2 << 12)
|
||||
#define ALC5632_MISC_AVC_TRGT_BOTH (3 << 12)
|
||||
#define ALC5632_MISC_HP_DEPOP_MODE1_EN (1 << 9)
|
||||
#define ALC5632_MISC_HP_DEPOP_MODE2_EN (1 << 8)
|
||||
#define ALC5632_MISC_HP_DEPOP_MUTE_L (1 << 7)
|
||||
#define ALC5632_MISC_HP_DEPOP_MUTE_R (1 << 6)
|
||||
#define ALC5632_MISC_HP_DEPOP_MUTE (1 << 5)
|
||||
#define ALC5632_MISC_GPIO_WAKEUP_CTRL (1 << 1)
|
||||
#define ALC5632_MISC_IRQOUT_INV_CTRL (1 << 0)
|
||||
|
||||
#define ALC5632_DAC_CLK_CTRL1 0x60
|
||||
#define ALC5632_DAC_CLK_CTRL2 0x62
|
||||
#define ALC5632_DAC_CLK_CTRL2_DIV1_2 (1 << 0)
|
||||
#define ALC5632_VOICE_DAC_PCM_CLK_CTRL1 0x64
|
||||
#define ALC5632_PSEUDO_SPATIAL_CTRL 0x68
|
||||
#define ALC5632_HID_CTRL_INDEX 0x6A
|
||||
#define ALC5632_HID_CTRL_DATA 0x6C
|
||||
#define ALC5632_EQ_CTRL 0x6E
|
||||
|
||||
/* undocumented */
|
||||
#define ALC5632_VENDOR_ID1 0x7C
|
||||
#define ALC5632_VENDOR_ID2 0x7E
|
||||
|
||||
#define ALC5632_MAX_REGISTER 0x7E
|
||||
|
||||
#endif
|
||||
5340
sound/soc/codecs/arizona.c
Normal file
5340
sound/soc/codecs/arizona.c
Normal file
File diff suppressed because it is too large
Load diff
500
sound/soc/codecs/arizona.h
Normal file
500
sound/soc/codecs/arizona.h
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* arizona.h - Wolfson Arizona class device shared support
|
||||
*
|
||||
* Copyright 2012 Wolfson Microelectronics plc
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ASOC_ARIZONA_H
|
||||
#define _ASOC_ARIZONA_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "wm_adsp.h"
|
||||
|
||||
#define ARIZONA_CLK_SYSCLK 1
|
||||
#define ARIZONA_CLK_ASYNCCLK 2
|
||||
#define ARIZONA_CLK_OPCLK 3
|
||||
#define ARIZONA_CLK_ASYNC_OPCLK 4
|
||||
#define ARIZONA_CLK_SYSCLK_2 5
|
||||
#define ARIZONA_CLK_SYSCLK_3 6
|
||||
#define ARIZONA_CLK_ASYNCCLK_2 7
|
||||
#define ARIZONA_CLK_DSPCLK 8
|
||||
|
||||
#define ARIZONA_CLK_SRC_MCLK1 0x0
|
||||
#define ARIZONA_CLK_SRC_MCLK2 0x1
|
||||
#define ARIZONA_CLK_SRC_FLL1 0x4
|
||||
#define ARIZONA_CLK_SRC_FLL2 0x5
|
||||
#define ARIZONA_CLK_SRC_FLL3 0x6
|
||||
#define ARIZONA_CLK_SRC_FLLAO_HI 0x7
|
||||
#define CLEARWATER_CLK_SRC_FLL1_DIV6 0x7
|
||||
#define ARIZONA_CLK_SRC_AIF1BCLK 0x8
|
||||
#define ARIZONA_CLK_SRC_AIF2BCLK 0x9
|
||||
#define ARIZONA_CLK_SRC_AIF3BCLK 0xa
|
||||
#define ARIZONA_CLK_SRC_AIF4BCLK 0xb
|
||||
#define ARIZONA_CLK_SRC_FLLAO 0xF
|
||||
|
||||
#define ARIZONA_FLL_SRC_NONE -1
|
||||
#define ARIZONA_FLL_SRC_MCLK1 0
|
||||
#define ARIZONA_FLL_SRC_MCLK2 1
|
||||
#define ARIZONA_FLL_SRC_SLIMCLK 3
|
||||
#define ARIZONA_FLL_SRC_FLL1 4
|
||||
#define ARIZONA_FLL_SRC_FLL2 5
|
||||
#define ARIZONA_FLL_SRC_AIF1BCLK 8
|
||||
#define ARIZONA_FLL_SRC_AIF2BCLK 9
|
||||
#define ARIZONA_FLL_SRC_AIF3BCLK 10
|
||||
#define ARIZONA_FLL_SRC_AIF4BCLK 11
|
||||
#define ARIZONA_FLL_SRC_AIF1LRCLK 12
|
||||
#define ARIZONA_FLL_SRC_AIF2LRCLK 13
|
||||
#define ARIZONA_FLL_SRC_AIF3LRCLK 14
|
||||
#define ARIZONA_FLL_SRC_AIF4LRCLK 15
|
||||
|
||||
#define ARIZONA_MIXER_VOL_MASK 0x00FE
|
||||
#define ARIZONA_MIXER_VOL_SHIFT 1
|
||||
#define ARIZONA_MIXER_VOL_WIDTH 7
|
||||
|
||||
#define ARIZONA_CLK_6MHZ 0
|
||||
#define ARIZONA_CLK_12MHZ 1
|
||||
#define ARIZONA_CLK_24MHZ 2
|
||||
#define ARIZONA_CLK_49MHZ 3
|
||||
#define ARIZONA_CLK_73MHZ 4
|
||||
#define CLEARWATER_CLK_98MHZ 4
|
||||
#define ARIZONA_CLK_98MHZ 5
|
||||
#define ARIZONA_CLK_147MHZ 6
|
||||
|
||||
#define CLEARWATER_DSP_CLK_9MHZ 0
|
||||
#define CLEARWATER_DSP_CLK_18MHZ 1
|
||||
#define CLEARWATER_DSP_CLK_36MHZ 2
|
||||
#define CLEARWATER_DSP_CLK_73MHZ 3
|
||||
#define CLEARWATER_DSP_CLK_147MHZ 4
|
||||
|
||||
#define ARIZONA_MAX_DAI 11
|
||||
#define ARIZONA_MAX_ADSP 7
|
||||
|
||||
#define ARIZONA_DVFS_SR1_RQ 0x001
|
||||
#define ARIZONA_DVFS_SR2_RQ 0x002
|
||||
#define ARIZONA_DVFS_SR3_RQ 0x004
|
||||
#define ARIZONA_DVFS_ASR1_RQ 0x008
|
||||
#define ARIZONA_DVFS_ASR2_RQ 0x010
|
||||
#define ARIZONA_DVFS_ADSP1_RQ 0x100
|
||||
|
||||
struct arizona;
|
||||
struct wm_adsp;
|
||||
struct arizona_jd_state;
|
||||
|
||||
struct arizona_dai_priv {
|
||||
int clk;
|
||||
};
|
||||
|
||||
struct arizona_priv {
|
||||
struct wm_adsp adsp[ARIZONA_MAX_ADSP];
|
||||
struct arizona *arizona;
|
||||
int sysclk;
|
||||
int asyncclk;
|
||||
int dspclk;
|
||||
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
|
||||
|
||||
int num_inputs;
|
||||
unsigned int in_pending;
|
||||
|
||||
unsigned int out_up_pending;
|
||||
unsigned int out_up_delay;
|
||||
unsigned int out_down_pending;
|
||||
unsigned int out_down_delay;
|
||||
|
||||
unsigned int spk_mute_cache;
|
||||
unsigned int spk_thr2_cache;
|
||||
unsigned int dvfs_reqs;
|
||||
struct mutex dvfs_lock;
|
||||
bool dvfs_cached;
|
||||
};
|
||||
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 134
|
||||
#define ARIZONA_V2_NUM_MIXER_INPUTS 146
|
||||
|
||||
extern const unsigned int arizona_mixer_tlv[];
|
||||
extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
|
||||
extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
|
||||
extern const char * const arizona_v2_mixer_texts[ARIZONA_V2_NUM_MIXER_INPUTS];
|
||||
extern unsigned int arizona_v2_mixer_values[ARIZONA_V2_NUM_MIXER_INPUTS];
|
||||
|
||||
#define ARIZONA_GAINMUX_CONTROLS(name, base) \
|
||||
SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1, \
|
||||
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
|
||||
arizona_mixer_tlv)
|
||||
|
||||
#define ARIZONA_MIXER_CONTROLS(name, base) \
|
||||
SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1, \
|
||||
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
|
||||
arizona_mixer_tlv), \
|
||||
SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 3, \
|
||||
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
|
||||
arizona_mixer_tlv), \
|
||||
SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 5, \
|
||||
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
|
||||
arizona_mixer_tlv), \
|
||||
SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 7, \
|
||||
ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
|
||||
arizona_mixer_tlv)
|
||||
|
||||
struct arizona_enum {
|
||||
struct soc_enum mixer_enum;
|
||||
int val;
|
||||
};
|
||||
|
||||
#define ARIZONA_ENUM_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
|
||||
struct arizona_enum name = { .mixer_enum.reg = xreg, \
|
||||
.mixer_enum.shift_l = xshift, .mixer_enum.shift_r = xshift, \
|
||||
.mixer_enum.mask = xmask, \
|
||||
.mixer_enum.items = ARRAY_SIZE(xtexts), \
|
||||
.mixer_enum.texts = xtexts, \
|
||||
.mixer_enum.values = xvalues, .val = 0 }
|
||||
|
||||
#define ARIZONA_MUX_ENUM_DECL(name, reg) \
|
||||
ARIZONA_ENUM_DECL(name, reg, 0, 0xff, \
|
||||
arizona_mixer_texts, arizona_mixer_values)
|
||||
|
||||
#define ARIZONA_MUX_CTL_DECL(xname) \
|
||||
const struct snd_kcontrol_new xname##_mux = { \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Route", \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = arizona_mux_get, \
|
||||
.put = arizona_mux_put, \
|
||||
.private_value = (unsigned long)&xname##_enum }
|
||||
|
||||
#define ARIZONA_MUX_ENUMS(name, base_reg) \
|
||||
static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \
|
||||
static ARIZONA_MUX_CTL_DECL(name)
|
||||
|
||||
#define ARIZONA_MIXER_ENUMS(name, base_reg) \
|
||||
ARIZONA_MUX_ENUMS(name##_in1, base_reg); \
|
||||
ARIZONA_MUX_ENUMS(name##_in2, base_reg + 2); \
|
||||
ARIZONA_MUX_ENUMS(name##_in3, base_reg + 4); \
|
||||
ARIZONA_MUX_ENUMS(name##_in4, base_reg + 6)
|
||||
|
||||
#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \
|
||||
ARIZONA_MUX_ENUMS(name##_aux1, base_reg); \
|
||||
ARIZONA_MUX_ENUMS(name##_aux2, base_reg + 8); \
|
||||
ARIZONA_MUX_ENUMS(name##_aux3, base_reg + 16); \
|
||||
ARIZONA_MUX_ENUMS(name##_aux4, base_reg + 24); \
|
||||
ARIZONA_MUX_ENUMS(name##_aux5, base_reg + 32); \
|
||||
ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)
|
||||
|
||||
#define CLEARWATER_MUX_ENUM_DECL(name, reg) \
|
||||
ARIZONA_ENUM_DECL(name, reg, 0, 0xff, \
|
||||
arizona_v2_mixer_texts, arizona_v2_mixer_values)
|
||||
|
||||
#define CLEARWATER_MUX_ENUMS(name, base_reg) \
|
||||
static CLEARWATER_MUX_ENUM_DECL(name##_enum, base_reg); \
|
||||
static ARIZONA_MUX_CTL_DECL(name)
|
||||
|
||||
#define CLEARWATER_MIXER_ENUMS(name, base_reg) \
|
||||
CLEARWATER_MUX_ENUMS(name##_in1, base_reg); \
|
||||
CLEARWATER_MUX_ENUMS(name##_in2, base_reg + 2); \
|
||||
CLEARWATER_MUX_ENUMS(name##_in3, base_reg + 4); \
|
||||
CLEARWATER_MUX_ENUMS(name##_in4, base_reg + 6)
|
||||
|
||||
#define CLEARWATER_DSP_AUX_ENUMS(name, base_reg) \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux1, base_reg); \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux2, base_reg + 8); \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux3, base_reg + 16); \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux4, base_reg + 24); \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux5, base_reg + 32); \
|
||||
CLEARWATER_MUX_ENUMS(name##_aux6, base_reg + 40)
|
||||
|
||||
#define ARIZONA_MUX(wname, wctrl) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = SND_SOC_NOPM, \
|
||||
.shift = 0, .kcontrol_news = wctrl, \
|
||||
.num_kcontrols = 1, .event = arizona_mux_event, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | \
|
||||
SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG}
|
||||
|
||||
#define ARIZONA_MUX_WIDGETS(name, name_str) \
|
||||
ARIZONA_MUX(name_str " Input", &name##_mux)
|
||||
|
||||
#define ARIZONA_MIXER_WIDGETS(name, name_str) \
|
||||
ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \
|
||||
ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \
|
||||
ARIZONA_MUX(name_str " Input 3", &name##_in3_mux), \
|
||||
ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
|
||||
SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
|
||||
|
||||
#define ARIZONA_DSP_WIDGETS(name, name_str) \
|
||||
ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \
|
||||
ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \
|
||||
ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \
|
||||
ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \
|
||||
ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \
|
||||
ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \
|
||||
ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
|
||||
ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
|
||||
|
||||
#define ARIZONA_MUX_ROUTES(widget, name) \
|
||||
{ widget, NULL, name " Input" }, \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Input")
|
||||
|
||||
#define ARIZONA_MIXER_ROUTES(widget, name) \
|
||||
{ widget, NULL, name " Mixer" }, \
|
||||
{ name " Mixer", NULL, name " Input 1" }, \
|
||||
{ name " Mixer", NULL, name " Input 2" }, \
|
||||
{ name " Mixer", NULL, name " Input 3" }, \
|
||||
{ name " Mixer", NULL, name " Input 4" }, \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Input 1"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Input 2"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
|
||||
|
||||
#define ARIZONA_DSP_ROUTES(name) \
|
||||
{ name, NULL, name " Preloader"}, \
|
||||
{ name " Preloader", NULL, name " Aux 1" }, \
|
||||
{ name " Preloader", NULL, name " Aux 2" }, \
|
||||
{ name " Preloader", NULL, name " Aux 3" }, \
|
||||
{ name " Preloader", NULL, name " Aux 4" }, \
|
||||
{ name " Preloader", NULL, name " Aux 5" }, \
|
||||
{ name " Preloader", NULL, name " Aux 6" }, \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
|
||||
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
|
||||
ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
|
||||
ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
|
||||
|
||||
#define ARIZONA_SAMPLE_RATE_CONTROL(name, domain) \
|
||||
SOC_ENUM(name, arizona_sample_rate[(domain) - 2])
|
||||
|
||||
#define ARIZONA_SAMPLE_RATE_CONTROL_DVFS(name, domain) \
|
||||
SOC_ENUM_EXT(name, arizona_sample_rate[(domain) - 2], \
|
||||
snd_soc_get_enum_double, \
|
||||
arizona_put_sample_rate_enum)
|
||||
|
||||
#define ARIZONA_EQ_CONTROL(xname, xbase) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
|
||||
.put = arizona_eq_coeff_put, .private_value = \
|
||||
((unsigned long)&(struct soc_bytes) { .base = xbase, \
|
||||
.num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) }
|
||||
|
||||
#define ARIZONA_LHPF_CONTROL(xname, xbase) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
|
||||
.put = arizona_lhpf_coeff_put, .private_value = \
|
||||
((unsigned long)&(struct soc_bytes) { .base = xbase, \
|
||||
.num_regs = 1 }) }
|
||||
|
||||
#define CLEARWATER_OSR_ENUM_SIZE 5
|
||||
#define ARIZONA_RATE_ENUM_SIZE 5
|
||||
#define ARIZONA_SYNC_RATE_ENUM_SIZE 3
|
||||
#define ARIZONA_ASYNC_RATE_ENUM_SIZE 2
|
||||
#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
|
||||
#define MOON_DFC_TYPE_ENUM_SIZE 5
|
||||
#define MOON_DFC_WIDTH_ENUM_SIZE 5
|
||||
|
||||
extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
|
||||
extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
|
||||
extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
|
||||
extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
|
||||
extern const char * const moon_dfc_width_text[MOON_DFC_WIDTH_ENUM_SIZE];
|
||||
extern const unsigned int moon_dfc_width_val[MOON_DFC_WIDTH_ENUM_SIZE];
|
||||
extern const char * const moon_dfc_type_text[MOON_DFC_TYPE_ENUM_SIZE];
|
||||
extern const unsigned int moon_dfc_type_val[MOON_DFC_TYPE_ENUM_SIZE];
|
||||
|
||||
extern const struct soc_enum arizona_sample_rate[];
|
||||
extern const struct soc_enum arizona_isrc_fsl[];
|
||||
extern const struct soc_enum arizona_isrc_fsh[];
|
||||
extern const struct soc_enum arizona_asrc_rate1;
|
||||
extern const struct soc_enum arizona_asrc_rate2;
|
||||
extern const struct soc_enum clearwater_asrc1_rate[];
|
||||
extern const struct soc_enum clearwater_asrc2_rate[];
|
||||
extern const struct soc_enum arizona_input_rate;
|
||||
extern const struct soc_enum arizona_output_rate;
|
||||
extern const struct soc_enum arizona_fx_rate;
|
||||
extern const struct soc_enum arizona_spdif_rate;
|
||||
extern const struct soc_enum moon_input_rate[];
|
||||
extern const struct soc_enum moon_dfc_width[];
|
||||
extern const struct soc_enum moon_dfc_type[];
|
||||
|
||||
extern const struct soc_enum arizona_in_vi_ramp;
|
||||
extern const struct soc_enum arizona_in_vd_ramp;
|
||||
|
||||
extern const struct soc_enum arizona_out_vi_ramp;
|
||||
extern const struct soc_enum arizona_out_vd_ramp;
|
||||
|
||||
extern const struct soc_enum arizona_lhpf1_mode;
|
||||
extern const struct soc_enum arizona_lhpf2_mode;
|
||||
extern const struct soc_enum arizona_lhpf3_mode;
|
||||
extern const struct soc_enum arizona_lhpf4_mode;
|
||||
|
||||
extern const struct soc_enum arizona_ng_hold;
|
||||
extern const struct soc_enum arizona_in_hpf_cut_enum;
|
||||
extern const struct soc_enum arizona_in_dmic_osr[];
|
||||
extern const struct soc_enum clearwater_in_dmic_osr[];
|
||||
|
||||
extern const struct soc_enum arizona_anc_input_src[];
|
||||
extern const struct soc_enum clearwater_anc_input_src[];
|
||||
extern const struct soc_enum arizona_anc_ng_enum;
|
||||
extern const struct soc_enum arizona_output_anc_src[];
|
||||
extern const struct soc_enum clearwater_output_anc_src_defs[];
|
||||
extern const struct soc_enum arizona_ip_mode[];
|
||||
|
||||
extern int arizona_ip_mode_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int moon_in_rate_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int moon_dfc_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int moon_osr_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int moon_lp_mode_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int clearwater_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int moon_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int moon_analog_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
|
||||
extern int arizona_mux_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
extern int arizona_mux_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
extern int arizona_mux_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
extern int arizona_put_sample_rate_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir);
|
||||
|
||||
extern int arizona_cache_and_clear_sources(struct arizona *arizona,
|
||||
const int *sources,
|
||||
unsigned int *cache,
|
||||
int lim);
|
||||
|
||||
extern int arizona_restore_sources(struct arizona *arizona,
|
||||
const int *sources,
|
||||
unsigned int *cache,
|
||||
int lim);
|
||||
|
||||
extern void clearwater_spin_sysclk(struct arizona *arizona);
|
||||
|
||||
extern const struct snd_soc_dai_ops arizona_dai_ops;
|
||||
extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
|
||||
|
||||
struct arizona_fll_cfg {
|
||||
unsigned int fin;
|
||||
unsigned int fvco;
|
||||
int n;
|
||||
int theta;
|
||||
int lambda;
|
||||
int refdiv;
|
||||
int outdiv;
|
||||
int fratio;
|
||||
int gain;
|
||||
int intg_gain;
|
||||
struct reg_sequence *patch;
|
||||
unsigned int patch_size;
|
||||
};
|
||||
|
||||
struct arizona_fll {
|
||||
struct arizona *arizona;
|
||||
int id;
|
||||
unsigned int base;
|
||||
unsigned int sync_offset;
|
||||
unsigned int vco_mult;
|
||||
|
||||
unsigned int fvco;
|
||||
int min_outdiv;
|
||||
int max_outdiv;
|
||||
int outdiv;
|
||||
unsigned int fout;
|
||||
int sync_src;
|
||||
unsigned int sync_freq;
|
||||
int ref_src;
|
||||
unsigned int ref_freq;
|
||||
struct arizona_fll_cfg ref_cfg;
|
||||
struct arizona_fll_cfg sync_cfg;
|
||||
};
|
||||
|
||||
extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
|
||||
extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
|
||||
extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
extern void arizona_init_dvfs(struct arizona_priv *priv);
|
||||
|
||||
extern int arizona_init_fll(struct arizona *arizona, int id, int base,
|
||||
int lock_irq, int ok_irq, struct arizona_fll *fll);
|
||||
extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout);
|
||||
extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout);
|
||||
extern int arizona_set_fll_ao(struct arizona_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout);
|
||||
|
||||
extern int arizona_init_spk(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_gpio(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_mono(struct snd_soc_codec *codec);
|
||||
extern int arizona_init_input(struct snd_soc_codec *codec);
|
||||
|
||||
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
|
||||
|
||||
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
||||
bool diff);
|
||||
|
||||
extern int arizona_set_hpdet_cb(struct snd_soc_codec *codec,
|
||||
void (*hpdet_cb)(unsigned int measurement));
|
||||
extern int arizona_set_micd_cb(struct snd_soc_codec *codec,
|
||||
void (*micd_cb)(bool mic));
|
||||
extern int arizona_set_ez2ctrl_cb(struct snd_soc_codec *codec,
|
||||
void (*ez2ctrl_trigger)(void));
|
||||
extern int arizona_set_custom_jd(struct snd_soc_codec *codec,
|
||||
const struct arizona_jd_state *custom_jd);
|
||||
|
||||
extern int clearwater_put_dre(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
extern struct regmap *arizona_get_regmap_dsp(struct snd_soc_codec *codec);
|
||||
|
||||
extern struct arizona_extcon_info *
|
||||
arizona_get_extcon_info(struct snd_soc_codec *codec);
|
||||
|
||||
extern int arizona_enable_force_bypass(struct snd_soc_codec *codec);
|
||||
extern int arizona_disable_force_bypass(struct snd_soc_codec *codec);
|
||||
|
||||
extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
|
||||
|
||||
#endif
|
||||
91
sound/soc/codecs/bt-sco.c
Normal file
91
sound/soc/codecs/bt-sco.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Driver for generic Bluetooth SCO link
|
||||
* Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("RX"),
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bt_sco_routes[] = {
|
||||
{ "Capture", NULL, "RX" },
|
||||
{ "TX", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver bt_sco_dai = {
|
||||
.name = "bt-sco-pcm",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
|
||||
.dapm_widgets = bt_sco_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
|
||||
.dapm_routes = bt_sco_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
|
||||
};
|
||||
|
||||
static int bt_sco_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
|
||||
&bt_sco_dai, 1);
|
||||
}
|
||||
|
||||
static int bt_sco_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id bt_sco_driver_ids[] = {
|
||||
{
|
||||
.name = "dfbmcs320",
|
||||
},
|
||||
{
|
||||
.name = "bt-sco",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
|
||||
|
||||
static struct platform_driver bt_sco_driver = {
|
||||
.driver = {
|
||||
.name = "bt-sco",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = bt_sco_probe,
|
||||
.remove = bt_sco_remove,
|
||||
.id_table = bt_sco_driver_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(bt_sco_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
3305
sound/soc/codecs/cod3026x.c
Executable file
3305
sound/soc/codecs/cod3026x.c
Executable file
File diff suppressed because it is too large
Load diff
1310
sound/soc/codecs/cod3026x.h
Executable file
1310
sound/soc/codecs/cod3026x.h
Executable file
File diff suppressed because it is too large
Load diff
3152
sound/soc/codecs/cod9002x.c
Executable file
3152
sound/soc/codecs/cod9002x.c
Executable file
File diff suppressed because it is too large
Load diff
1362
sound/soc/codecs/cod9002x.h
Executable file
1362
sound/soc/codecs/cod9002x.h
Executable file
File diff suppressed because it is too large
Load diff
198
sound/soc/codecs/cq93vc.c
Normal file
198
sound/soc/codecs/cq93vc.c
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc
|
||||
*
|
||||
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/davinci_voicecodec.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
|
||||
SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
|
||||
SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
|
||||
};
|
||||
|
||||
static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 reg;
|
||||
|
||||
if (mute)
|
||||
reg = DAVINCI_VC_REG09_MUTE;
|
||||
else
|
||||
reg = 0;
|
||||
|
||||
snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
|
||||
reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
switch (freq) {
|
||||
case 22579200:
|
||||
case 27000000:
|
||||
case 33868800:
|
||||
davinci_vc->cq93vc.sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_ON);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_OFF);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* force all power off */
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_OFF);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CQ93VC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
|
||||
#define CQ93VC_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops cq93vc_dai_ops = {
|
||||
.digital_mute = cq93vc_mute,
|
||||
.set_sysclk = cq93vc_set_dai_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cq93vc_dai = {
|
||||
.name = "cq93vc-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = CQ93VC_RATES,
|
||||
.formats = CQ93VC_FORMATS,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = CQ93VC_RATES,
|
||||
.formats = CQ93VC_FORMATS,},
|
||||
.ops = &cq93vc_dai_ops,
|
||||
};
|
||||
|
||||
static int cq93vc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
|
||||
/* Off, with power on */
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap *cq93vc_get_regmap(struct device *dev)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = dev->platform_data;
|
||||
|
||||
return davinci_vc->regmap;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
|
||||
.set_bias_level = cq93vc_set_bias_level,
|
||||
.probe = cq93vc_probe,
|
||||
.remove = cq93vc_remove,
|
||||
.resume = cq93vc_resume,
|
||||
.get_regmap = cq93vc_get_regmap,
|
||||
.controls = cq93vc_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
|
||||
};
|
||||
|
||||
static int cq93vc_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_cq93vc, &cq93vc_dai, 1);
|
||||
}
|
||||
|
||||
static int cq93vc_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cq93vc_codec_driver = {
|
||||
.driver = {
|
||||
.name = "cq93vc-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = cq93vc_platform_probe,
|
||||
.remove = cq93vc_platform_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(cq93vc_codec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC CQ0093 Voice Codec Driver");
|
||||
MODULE_AUTHOR("Miguel Aguilar");
|
||||
MODULE_LICENSE("GPL");
|
||||
631
sound/soc/codecs/cs35l32.c
Normal file
631
sound/soc/codecs/cs35l32.c
Normal file
|
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* cs35l32.c -- CS35L32 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2014 CirrusLogic, Inc.
|
||||
*
|
||||
* Author: Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_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 <dt-bindings/sound/cs35l32.h>
|
||||
|
||||
#include "cs35l32.h"
|
||||
|
||||
#define CS35L32_NUM_SUPPLIES 2
|
||||
static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
|
||||
"VA",
|
||||
"VP",
|
||||
};
|
||||
|
||||
struct cs35l32_private {
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_codec *codec;
|
||||
struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
|
||||
struct cs35l32_platform_data pdata;
|
||||
struct gpio_desc *reset_gpio;
|
||||
};
|
||||
|
||||
static const struct reg_default cs35l32_reg_defaults[] = {
|
||||
|
||||
{ 0x06, 0x04 }, /* Power Ctl 1 */
|
||||
{ 0x07, 0xE8 }, /* Power Ctl 2 */
|
||||
{ 0x08, 0x40 }, /* Clock Ctl */
|
||||
{ 0x09, 0x20 }, /* Low Battery Threshold */
|
||||
{ 0x0A, 0x00 }, /* Voltage Monitor [RO] */
|
||||
{ 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
|
||||
{ 0x0C, 0x07 }, /* IMON Scaling */
|
||||
{ 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
|
||||
{ 0x0F, 0x20 }, /* Serial Port Control */
|
||||
{ 0x10, 0x14 }, /* Class D Amp CTL */
|
||||
{ 0x11, 0x00 }, /* Protection Release CTL */
|
||||
{ 0x12, 0xFF }, /* Interrupt Mask 1 */
|
||||
{ 0x13, 0xFF }, /* Interrupt Mask 2 */
|
||||
{ 0x14, 0xFF }, /* Interrupt Mask 3 */
|
||||
{ 0x19, 0x00 }, /* LED Flash Mode Current */
|
||||
{ 0x1A, 0x00 }, /* LED Movie Mode Current */
|
||||
{ 0x1B, 0x20 }, /* LED Flash Timer */
|
||||
{ 0x1C, 0x00 }, /* LED Flash Inhibit Current */
|
||||
};
|
||||
|
||||
static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS35L32_DEVID_AB:
|
||||
case CS35L32_DEVID_CD:
|
||||
case CS35L32_DEVID_E:
|
||||
case CS35L32_FAB_ID:
|
||||
case CS35L32_REV_ID:
|
||||
case CS35L32_PWRCTL1:
|
||||
case CS35L32_PWRCTL2:
|
||||
case CS35L32_CLK_CTL:
|
||||
case CS35L32_BATT_THRESHOLD:
|
||||
case CS35L32_VMON:
|
||||
case CS35L32_BST_CPCP_CTL:
|
||||
case CS35L32_IMON_SCALING:
|
||||
case CS35L32_AUDIO_LED_MNGR:
|
||||
case CS35L32_ADSP_CTL:
|
||||
case CS35L32_CLASSD_CTL:
|
||||
case CS35L32_PROTECT_CTL:
|
||||
case CS35L32_INT_MASK_1:
|
||||
case CS35L32_INT_MASK_2:
|
||||
case CS35L32_INT_MASK_3:
|
||||
case CS35L32_INT_STATUS_1:
|
||||
case CS35L32_INT_STATUS_2:
|
||||
case CS35L32_INT_STATUS_3:
|
||||
case CS35L32_LED_STATUS:
|
||||
case CS35L32_FLASH_MODE:
|
||||
case CS35L32_MOVIE_MODE:
|
||||
case CS35L32_FLASH_TIMER:
|
||||
case CS35L32_FLASH_INHIBIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS35L32_DEVID_AB:
|
||||
case CS35L32_DEVID_CD:
|
||||
case CS35L32_DEVID_E:
|
||||
case CS35L32_FAB_ID:
|
||||
case CS35L32_REV_ID:
|
||||
case CS35L32_INT_STATUS_1:
|
||||
case CS35L32_INT_STATUS_2:
|
||||
case CS35L32_INT_STATUS_3:
|
||||
case CS35L32_LED_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS35L32_INT_STATUS_1:
|
||||
case CS35L32_INT_STATUS_2:
|
||||
case CS35L32_INT_STATUS_3:
|
||||
case CS35L32_LED_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
|
||||
|
||||
static const struct snd_kcontrol_new imon_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
|
||||
|
||||
static const struct snd_kcontrol_new vmon_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
|
||||
|
||||
static const struct snd_kcontrol_new vpmon_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
|
||||
|
||||
static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
|
||||
3, 0x04, 1, classd_ctl_tlv),
|
||||
SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
|
||||
SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
|
||||
SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
|
||||
|
||||
SND_SOC_DAPM_INPUT("VP"),
|
||||
SND_SOC_DAPM_INPUT("ISENSE"),
|
||||
SND_SOC_DAPM_INPUT("VSENSE"),
|
||||
|
||||
SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
|
||||
SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
|
||||
SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
|
||||
|
||||
{"Speaker", NULL, "BOOST"},
|
||||
|
||||
{"VMON ADC", NULL, "VSENSE"},
|
||||
{"IMON ADC", NULL, "ISENSE"},
|
||||
{"VPMON ADC", NULL, "VP"},
|
||||
|
||||
{"SDOUT", "Switch", "VMON ADC"},
|
||||
{"SDOUT", "Switch", "IMON ADC"},
|
||||
{"SDOUT", "Switch", "VPMON ADC"},
|
||||
|
||||
{"Capture", NULL, "SDOUT"},
|
||||
};
|
||||
|
||||
static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
|
||||
CS35L32_ADSP_MASTER_MASK,
|
||||
CS35L32_ADSP_MASTER_MASK);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
|
||||
CS35L32_ADSP_MASTER_MASK, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
return snd_soc_update_bits(codec, CS35L32_PWRCTL2,
|
||||
CS35L32_SDOUT_3ST, tristate << 3);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops cs35l32_ops = {
|
||||
.set_fmt = cs35l32_set_dai_fmt,
|
||||
.set_tristate = cs35l32_set_tristate,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs35l32_dai[] = {
|
||||
{
|
||||
.name = "cs35l32-monitor",
|
||||
.id = 0,
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = CS35L32_RATES,
|
||||
.formats = CS35L32_FORMATS,
|
||||
},
|
||||
.ops = &cs35l32_ops,
|
||||
.symmetric_rates = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
|
||||
int clk_id, int source, unsigned int freq, int dir)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
switch (freq) {
|
||||
case 6000000:
|
||||
val = CS35L32_MCLK_RATIO;
|
||||
break;
|
||||
case 12000000:
|
||||
val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
|
||||
break;
|
||||
case 6144000:
|
||||
val = 0;
|
||||
break;
|
||||
case 12288000:
|
||||
val = CS35L32_MCLK_DIV2_MASK;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_update_bits(codec, CS35L32_CLK_CTL,
|
||||
CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
|
||||
.set_sysclk = cs35l32_codec_set_sysclk,
|
||||
|
||||
.dapm_widgets = cs35l32_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets),
|
||||
.dapm_routes = cs35l32_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map),
|
||||
|
||||
.controls = cs35l32_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs35l32_snd_controls),
|
||||
};
|
||||
|
||||
/* Current and threshold powerup sequence Pg37 in datasheet */
|
||||
static const struct reg_default cs35l32_monitor_patch[] = {
|
||||
|
||||
{ 0x00, 0x99 },
|
||||
{ 0x48, 0x17 },
|
||||
{ 0x49, 0x56 },
|
||||
{ 0x43, 0x01 },
|
||||
{ 0x3B, 0x62 },
|
||||
{ 0x3C, 0x80 },
|
||||
{ 0x00, 0x00 },
|
||||
};
|
||||
|
||||
static struct regmap_config cs35l32_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = CS35L32_MAX_REGISTER,
|
||||
.reg_defaults = cs35l32_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
|
||||
.volatile_reg = cs35l32_volatile_register,
|
||||
.readable_reg = cs35l32_readable_register,
|
||||
.precious_reg = cs35l32_precious_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
|
||||
struct cs35l32_platform_data *pdata)
|
||||
{
|
||||
struct device_node *np = i2c_client->dev.of_node;
|
||||
unsigned int val;
|
||||
|
||||
if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
|
||||
pdata->sdout_share = val;
|
||||
|
||||
of_property_read_u32(np, "cirrus,boost-manager", &val);
|
||||
switch (val) {
|
||||
case CS35L32_BOOST_MGR_AUTO:
|
||||
case CS35L32_BOOST_MGR_AUTO_AUDIO:
|
||||
case CS35L32_BOOST_MGR_BYPASS:
|
||||
case CS35L32_BOOST_MGR_FIXED:
|
||||
pdata->boost_mng = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c_client->dev,
|
||||
"Wrong cirrus,boost-manager DT value %d\n", val);
|
||||
pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "cirrus,sdout-datacfg", &val);
|
||||
switch (val) {
|
||||
case CS35L32_DATA_CFG_LR_VP:
|
||||
case CS35L32_DATA_CFG_LR_STAT:
|
||||
case CS35L32_DATA_CFG_LR:
|
||||
case CS35L32_DATA_CFG_LR_VPSTAT:
|
||||
pdata->sdout_datacfg = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c_client->dev,
|
||||
"Wrong cirrus,sdout-datacfg DT value %d\n", val);
|
||||
pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "cirrus,battery-threshold", &val);
|
||||
switch (val) {
|
||||
case CS35L32_BATT_THRESH_3_1V:
|
||||
case CS35L32_BATT_THRESH_3_2V:
|
||||
case CS35L32_BATT_THRESH_3_3V:
|
||||
case CS35L32_BATT_THRESH_3_4V:
|
||||
pdata->batt_thresh = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c_client->dev,
|
||||
"Wrong cirrus,battery-threshold DT value %d\n", val);
|
||||
pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "cirrus,battery-recovery", &val);
|
||||
switch (val) {
|
||||
case CS35L32_BATT_RECOV_3_1V:
|
||||
case CS35L32_BATT_RECOV_3_2V:
|
||||
case CS35L32_BATT_RECOV_3_3V:
|
||||
case CS35L32_BATT_RECOV_3_4V:
|
||||
case CS35L32_BATT_RECOV_3_5V:
|
||||
case CS35L32_BATT_RECOV_3_6V:
|
||||
pdata->batt_recov = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c_client->dev,
|
||||
"Wrong cirrus,battery-recovery DT value %d\n", val);
|
||||
pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cs35l32_private *cs35l32;
|
||||
struct cs35l32_platform_data *pdata =
|
||||
dev_get_platdata(&i2c_client->dev);
|
||||
int ret, i;
|
||||
unsigned int devid = 0;
|
||||
unsigned int reg;
|
||||
|
||||
|
||||
cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private),
|
||||
GFP_KERNEL);
|
||||
if (!cs35l32) {
|
||||
dev_err(&i2c_client->dev, "could not allocate codec\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs35l32);
|
||||
|
||||
cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
|
||||
if (IS_ERR(cs35l32->regmap)) {
|
||||
ret = PTR_ERR(cs35l32->regmap);
|
||||
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
cs35l32->pdata = *pdata;
|
||||
} else {
|
||||
pdata = devm_kzalloc(&i2c_client->dev,
|
||||
sizeof(struct cs35l32_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&i2c_client->dev, "could not allocate pdata\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (i2c_client->dev.of_node) {
|
||||
ret = cs35l32_handle_of_data(i2c_client,
|
||||
&cs35l32->pdata);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
|
||||
cs35l32->supplies[i].supply = cs35l32_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&i2c_client->dev,
|
||||
ARRAY_SIZE(cs35l32->supplies),
|
||||
cs35l32->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c_client->dev,
|
||||
"Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
|
||||
cs35l32->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c_client->dev,
|
||||
"Failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset the Device */
|
||||
cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
|
||||
"reset-gpios");
|
||||
if (IS_ERR(cs35l32->reset_gpio)) {
|
||||
ret = PTR_ERR(cs35l32->reset_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
|
||||
cs35l32->reset_gpio = NULL;
|
||||
} else {
|
||||
ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
|
||||
}
|
||||
|
||||
/* initialize codec */
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®);
|
||||
devid = (reg & 0xFF) << 12;
|
||||
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®);
|
||||
devid |= (reg & 0xFF) << 4;
|
||||
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®);
|
||||
devid |= (reg & 0xF0) >> 4;
|
||||
|
||||
if (devid != CS35L32_CHIP_ID) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&i2c_client->dev,
|
||||
"CS35L32 Device ID (%X). Expected %X\n",
|
||||
devid, CS35L32_CHIP_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "Get Revision ID failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
|
||||
ARRAY_SIZE(cs35l32_monitor_patch));
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev,
|
||||
"Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
|
||||
|
||||
/* Setup VBOOST Management */
|
||||
if (cs35l32->pdata.boost_mng)
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
|
||||
CS35L32_BOOST_MASK,
|
||||
cs35l32->pdata.boost_mng);
|
||||
|
||||
/* Setup ADSP Format Config */
|
||||
if (cs35l32->pdata.sdout_share)
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
|
||||
CS35L32_ADSP_SHARE_MASK,
|
||||
cs35l32->pdata.sdout_share << 3);
|
||||
|
||||
/* Setup ADSP Data Configuration */
|
||||
if (cs35l32->pdata.sdout_datacfg)
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
|
||||
CS35L32_ADSP_DATACFG_MASK,
|
||||
cs35l32->pdata.sdout_datacfg << 4);
|
||||
|
||||
/* Setup Low Battery Recovery */
|
||||
if (cs35l32->pdata.batt_recov)
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
|
||||
CS35L32_BATT_REC_MASK,
|
||||
cs35l32->pdata.batt_recov << 1);
|
||||
|
||||
/* Setup Low Battery Threshold */
|
||||
if (cs35l32->pdata.batt_thresh)
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
|
||||
CS35L32_BATT_THRESH_MASK,
|
||||
cs35l32->pdata.batt_thresh << 4);
|
||||
|
||||
/* Power down the AMP */
|
||||
regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
|
||||
CS35L32_PDN_AMP);
|
||||
|
||||
/* Clear MCLK Error Bit since we don't have the clock yet */
|
||||
ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_dev_cs35l32, cs35l32_dai,
|
||||
ARRAY_SIZE(cs35l32_dai));
|
||||
if (ret < 0)
|
||||
goto err_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
|
||||
cs35l32->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
|
||||
{
|
||||
struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
|
||||
|
||||
snd_soc_unregister_codec(&i2c_client->dev);
|
||||
|
||||
/* Hold down reset */
|
||||
if (cs35l32->reset_gpio)
|
||||
gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int cs35l32_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(cs35l32->regmap, true);
|
||||
regcache_mark_dirty(cs35l32->regmap);
|
||||
|
||||
/* Hold down reset */
|
||||
if (cs35l32->reset_gpio)
|
||||
gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
|
||||
|
||||
/* remove power */
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
|
||||
cs35l32->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l32_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/* Enable power */
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
|
||||
cs35l32->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable supplies: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cs35l32->reset_gpio)
|
||||
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
|
||||
|
||||
regcache_cache_only(cs35l32->regmap, false);
|
||||
regcache_sync(cs35l32->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops cs35l32_runtime_pm = {
|
||||
SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id cs35l32_of_match[] = {
|
||||
{ .compatible = "cirrus,cs35l32", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs35l32_of_match);
|
||||
|
||||
|
||||
static const struct i2c_device_id cs35l32_id[] = {
|
||||
{"cs35l32", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, cs35l32_id);
|
||||
|
||||
static struct i2c_driver cs35l32_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs35l32",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cs35l32_runtime_pm,
|
||||
.of_match_table = cs35l32_of_match,
|
||||
},
|
||||
.id_table = cs35l32_id,
|
||||
.probe = cs35l32_i2c_probe,
|
||||
.remove = cs35l32_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs35l32_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CS35L32 driver");
|
||||
MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
93
sound/soc/codecs/cs35l32.h
Normal file
93
sound/soc/codecs/cs35l32.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* cs35l32.h -- CS35L32 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2014 CirrusLogic, Inc.
|
||||
*
|
||||
* Author: Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS35L32_H__
|
||||
#define __CS35L32_H__
|
||||
|
||||
struct cs35l32_platform_data {
|
||||
/* Low Battery Threshold */
|
||||
unsigned int batt_thresh;
|
||||
/* Low Battery Recovery */
|
||||
unsigned int batt_recov;
|
||||
/* LED Current Management*/
|
||||
unsigned int led_mng;
|
||||
/* Audio Gain w/ LED */
|
||||
unsigned int audiogain_mng;
|
||||
/* Boost Management */
|
||||
unsigned int boost_mng;
|
||||
/* Data CFG for DUAL device */
|
||||
unsigned int sdout_datacfg;
|
||||
/* SDOUT Sharing */
|
||||
unsigned int sdout_share;
|
||||
};
|
||||
|
||||
#define CS35L32_CHIP_ID 0x00035A32
|
||||
#define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */
|
||||
#define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */
|
||||
#define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */
|
||||
#define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */
|
||||
#define CS35L32_REV_ID 0x05 /* Revision ID [RO] */
|
||||
#define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */
|
||||
#define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */
|
||||
#define CS35L32_CLK_CTL 0x08 /* Clock Ctl */
|
||||
#define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */
|
||||
#define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */
|
||||
#define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */
|
||||
#define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */
|
||||
#define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */
|
||||
#define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */
|
||||
#define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */
|
||||
#define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */
|
||||
#define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */
|
||||
#define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */
|
||||
#define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */
|
||||
#define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */
|
||||
#define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */
|
||||
#define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */
|
||||
#define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */
|
||||
#define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */
|
||||
#define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */
|
||||
#define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */
|
||||
#define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */
|
||||
#define CS35L32_MAX_REGISTER 0x1C
|
||||
|
||||
#define CS35L32_MCLK_DIV2 0x01
|
||||
#define CS35L32_MCLK_RATIO 0x01
|
||||
#define CS35L32_MCLKDIS 0x80
|
||||
#define CS35L32_PDN_ALL 0x01
|
||||
#define CS35L32_PDN_AMP 0x80
|
||||
#define CS35L32_PDN_BOOST 0x04
|
||||
#define CS35L32_PDN_IMON 0x40
|
||||
#define CS35L32_PDN_VMON 0x80
|
||||
#define CS35L32_PDN_VPMON 0x20
|
||||
#define CS35L32_PDN_ADSP 0x08
|
||||
|
||||
#define CS35L32_MCLK_DIV2_MASK 0x40
|
||||
#define CS35L32_MCLK_RATIO_MASK 0x01
|
||||
#define CS35L32_MCLK_MASK 0x41
|
||||
#define CS35L32_ADSP_MASTER_MASK 0x40
|
||||
#define CS35L32_BOOST_MASK 0x03
|
||||
#define CS35L32_GAIN_MGR_MASK 0x08
|
||||
#define CS35L32_ADSP_SHARE_MASK 0x08
|
||||
#define CS35L32_ADSP_DATACFG_MASK 0x30
|
||||
#define CS35L32_SDOUT_3ST 0x80
|
||||
#define CS35L32_BATT_REC_MASK 0x0E
|
||||
#define CS35L32_BATT_THRESH_MASK 0x30
|
||||
|
||||
#define CS35L32_RATES (SNDRV_PCM_RATE_48000)
|
||||
#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
|
||||
#endif
|
||||
683
sound/soc/codecs/cs4265.c
Normal file
683
sound/soc/codecs/cs4265.c
Normal file
|
|
@ -0,0 +1,683 @@
|
|||
/*
|
||||
* cs4265.c -- CS4265 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2014 Cirrus Logic, Inc.
|
||||
*
|
||||
* Author: Paul Handrigan <paul.handrigan@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 device *dev;
|
||||
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_PWRCTL:
|
||||
case CS4265_DAC_CTL:
|
||||
case CS4265_ADC_CTL:
|
||||
case CS4265_MCLK_FREQ:
|
||||
case CS4265_SIG_SEL:
|
||||
case CS4265_CHB_PGA_CTL:
|
||||
case CS4265_CHA_PGA_CTL:
|
||||
case CS4265_ADC_CTL2:
|
||||
case CS4265_DAC_CHA_VOL:
|
||||
case CS4265_DAC_CHB_VOL:
|
||||
case CS4265_DAC_CTL2:
|
||||
case CS4265_SPDIF_CTL1:
|
||||
case CS4265_SPDIF_CTL2:
|
||||
case CS4265_INT_MASK:
|
||||
case CS4265_STATUS_MODE_MSB:
|
||||
case CS4265_STATUS_MODE_LSB:
|
||||
case CS4265_CHIP_ID:
|
||||
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", 0,
|
||||
1, 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", SND_SOC_NOPM, 0, 0,
|
||||
&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"},
|
||||
|
||||
{"ADC Mux", "LINEIN", "LINEINL"},
|
||||
{"ADC Mux", "LINEIN", "LINEINR"},
|
||||
{"ADC Mux", "MIC", "MICL"},
|
||||
{"ADC Mux", "MIC", "MICR"},
|
||||
{"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_codec *codec = codec_dai->codec;
|
||||
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
|
||||
if (clk_id != 0) {
|
||||
dev_err(codec->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(codec->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_codec *codec = codec_dai->codec;
|
||||
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 iface = 0;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
snd_soc_update_bits(codec, CS4265_ADC_CTL,
|
||||
CS4265_ADC_MASTER,
|
||||
CS4265_ADC_MASTER);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
snd_soc_update_bits(codec, 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_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
if (mute) {
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_MUTE,
|
||||
CS4265_DAC_CTL_MUTE);
|
||||
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
|
||||
CS4265_SPDIF_CTL2_MUTE,
|
||||
CS4265_SPDIF_CTL2_MUTE);
|
||||
} else {
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_MUTE,
|
||||
0);
|
||||
snd_soc_update_bits(codec, 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_codec *codec = dai->codec;
|
||||
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
|
||||
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_update_bits(codec, CS4265_ADC_CTL,
|
||||
CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
|
||||
snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
|
||||
CS4265_MCLK_FREQ_MASK,
|
||||
clk_map_table[index].mclkdiv << 4);
|
||||
|
||||
} else {
|
||||
dev_err(codec->dev, "can't get correct mclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_DIF, (1 << 4));
|
||||
snd_soc_update_bits(codec, CS4265_ADC_CTL,
|
||||
CS4265_ADC_DIF, (1 << 4));
|
||||
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
|
||||
CS4265_SPDIF_CTL2_DIF, (1 << 6));
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
if (params_width(params) == 16) {
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_DIF, (1 << 5));
|
||||
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
|
||||
CS4265_SPDIF_CTL2_DIF, (1 << 7));
|
||||
} else {
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_DIF, (3 << 5));
|
||||
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
|
||||
CS4265_SPDIF_CTL2_DIF, (1 << 7));
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
snd_soc_update_bits(codec, CS4265_DAC_CTL,
|
||||
CS4265_DAC_CTL_DIF, 0);
|
||||
snd_soc_update_bits(codec, CS4265_ADC_CTL,
|
||||
CS4265_ADC_DIF, 0);
|
||||
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
|
||||
CS4265_SPDIF_CTL2_DIF, (1 << 6));
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4265_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
snd_soc_update_bits(codec, CS4265_PWRCTL,
|
||||
CS4265_PWRCTL_PDN, 0);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, CS4265_PWRCTL,
|
||||
CS4265_PWRCTL_PDN,
|
||||
CS4265_PWRCTL_PDN);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, CS4265_PWRCTL,
|
||||
CS4265_PWRCTL_PDN,
|
||||
CS4265_PWRCTL_PDN);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
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)
|
||||
|
||||
static const struct snd_soc_dai_ops cs4265_ops = {
|
||||
.hw_params = cs4265_pcm_hw_params,
|
||||
.digital_mute = cs4265_digital_mute,
|
||||
.set_fmt = cs4265_set_fmt,
|
||||
.set_sysclk = cs4265_set_sysclk,
|
||||
};
|
||||
|
||||
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_codec_driver soc_codec_cs4265 = {
|
||||
.set_bias_level = cs4265_set_bias_level,
|
||||
|
||||
.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),
|
||||
|
||||
.controls = cs4265_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs4265_snd_controls),
|
||||
};
|
||||
|
||||
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 = 0;
|
||||
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->dev = &i2c_client->dev;
|
||||
|
||||
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(&i2c_client->dev,
|
||||
"reset-gpios");
|
||||
if (IS_ERR(cs4265->reset_gpio)) {
|
||||
ret = PTR_ERR(cs4265->reset_gpio);
|
||||
if (ret != -ENOENT && ret != -ENOSYS)
|
||||
return ret;
|
||||
|
||||
cs4265->reset_gpio = NULL;
|
||||
} else {
|
||||
ret = gpiod_direction_output(cs4265->reset_gpio, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
mdelay(1);
|
||||
gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
|
||||
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs4265);
|
||||
|
||||
ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, ®);
|
||||
devid = reg & CS4265_CHIP_ID_MASK;
|
||||
if (devid != CS4265_CHIP_ID_VAL) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&i2c_client->dev,
|
||||
"CS4265 Device ID (%X). Expected %X\n",
|
||||
devid, CS4265_CHIP_ID);
|
||||
return ret;
|
||||
}
|
||||
dev_info(&i2c_client->dev,
|
||||
"CS4265 Version %x\n",
|
||||
reg & CS4265_REV_ID_MASK);
|
||||
|
||||
regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_cs4265, cs4265_dai,
|
||||
ARRAY_SIZE(cs4265_dai));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs4265_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
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",
|
||||
.owner = THIS_MODULE,
|
||||
.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");
|
||||
64
sound/soc/codecs/cs4265.h
Normal file
64
sound/soc/codecs/cs4265.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* cs4265.h -- CS4265 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2014 Cirrus Logic, Inc.
|
||||
*
|
||||
* Author: Paul Handrigan <paul.handrigan@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS4265_H__
|
||||
#define __CS4265_H__
|
||||
|
||||
#define CS4265_CHIP_ID 0x1
|
||||
#define CS4265_CHIP_ID_VAL 0xD0
|
||||
#define CS4265_CHIP_ID_MASK 0xF0
|
||||
#define CS4265_REV_ID_MASK 0x0F
|
||||
|
||||
#define CS4265_PWRCTL 0x02
|
||||
#define CS4265_PWRCTL_PDN 1
|
||||
|
||||
#define CS4265_DAC_CTL 0x3
|
||||
#define CS4265_DAC_CTL_MUTE (1 << 2)
|
||||
#define CS4265_DAC_CTL_DIF (3 << 4)
|
||||
|
||||
#define CS4265_ADC_CTL 0x4
|
||||
#define CS4265_ADC_MASTER 1
|
||||
#define CS4265_ADC_DIF (1 << 4)
|
||||
#define CS4265_ADC_FM (3 << 6)
|
||||
|
||||
#define CS4265_MCLK_FREQ 0x5
|
||||
#define CS4265_MCLK_FREQ_MASK (7 << 4)
|
||||
|
||||
#define CS4265_SIG_SEL 0x6
|
||||
#define CS4265_SIG_SEL_LOOP (1 << 1)
|
||||
|
||||
#define CS4265_CHB_PGA_CTL 0x7
|
||||
#define CS4265_CHA_PGA_CTL 0x8
|
||||
|
||||
#define CS4265_ADC_CTL2 0x9
|
||||
|
||||
#define CS4265_DAC_CHA_VOL 0xA
|
||||
#define CS4265_DAC_CHB_VOL 0xB
|
||||
|
||||
#define CS4265_DAC_CTL2 0xC
|
||||
|
||||
#define CS4265_INT_STATUS 0xD
|
||||
#define CS4265_INT_MASK 0xE
|
||||
#define CS4265_STATUS_MODE_MSB 0xF
|
||||
#define CS4265_STATUS_MODE_LSB 0x10
|
||||
|
||||
#define CS4265_SPDIF_CTL1 0x11
|
||||
|
||||
#define CS4265_SPDIF_CTL2 0x12
|
||||
#define CS4265_SPDIF_CTL2_MUTE (1 << 4)
|
||||
#define CS4265_SPDIF_CTL2_DIF (3 << 6)
|
||||
|
||||
#define CS4265_C_DATA_BUFF 0x13
|
||||
#define CS4265_MAX_REGISTER 0x2A
|
||||
|
||||
#endif
|
||||
766
sound/soc/codecs/cs4270.c
Normal file
766
sound/soc/codecs/cs4270.c
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
/*
|
||||
* CS4270 ALSA SoC (ASoC) codec driver
|
||||
*
|
||||
* Author: Timur Tabi <timur@freescale.com>
|
||||
*
|
||||
* Copyright 2007-2009 Freescale Semiconductor, Inc. This file is licensed
|
||||
* under the terms of the GNU General Public License version 2. This
|
||||
* program is licensed "as is" without any warranty of any kind, whether
|
||||
* express or implied.
|
||||
*
|
||||
* This is an ASoC device driver for the Cirrus Logic CS4270 codec.
|
||||
*
|
||||
* Current features/limitations:
|
||||
*
|
||||
* - Software mode is supported. Stand-alone mode is not supported.
|
||||
* - Only I2C is supported, not SPI
|
||||
* - Support for master and slave mode
|
||||
* - The machine driver's 'startup' function must call
|
||||
* cs4270_set_dai_sysclk() with the value of MCLK.
|
||||
* - Only I2S and left-justified modes are supported
|
||||
* - Power management is supported
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.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)
|
||||
|
||||
/* CS4270 registers addresses */
|
||||
#define CS4270_CHIPID 0x01 /* Chip ID */
|
||||
#define CS4270_PWRCTL 0x02 /* Power Control */
|
||||
#define CS4270_MODE 0x03 /* Mode Control */
|
||||
#define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */
|
||||
#define CS4270_TRANS 0x05 /* Transition Control */
|
||||
#define CS4270_MUTE 0x06 /* Mute Control */
|
||||
#define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */
|
||||
#define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */
|
||||
|
||||
#define CS4270_FIRSTREG 0x01
|
||||
#define CS4270_LASTREG 0x08
|
||||
#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
|
||||
#define CS4270_I2C_INCR 0x80
|
||||
|
||||
/* Bit masks for the CS4270 registers */
|
||||
#define CS4270_CHIPID_ID 0xF0
|
||||
#define CS4270_CHIPID_REV 0x0F
|
||||
#define CS4270_PWRCTL_FREEZE 0x80
|
||||
#define CS4270_PWRCTL_PDN_ADC 0x20
|
||||
#define CS4270_PWRCTL_PDN_DAC 0x02
|
||||
#define CS4270_PWRCTL_PDN 0x01
|
||||
#define CS4270_PWRCTL_PDN_ALL \
|
||||
(CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN)
|
||||
#define CS4270_MODE_SPEED_MASK 0x30
|
||||
#define CS4270_MODE_1X 0x00
|
||||
#define CS4270_MODE_2X 0x10
|
||||
#define CS4270_MODE_4X 0x20
|
||||
#define CS4270_MODE_SLAVE 0x30
|
||||
#define CS4270_MODE_DIV_MASK 0x0E
|
||||
#define CS4270_MODE_DIV1 0x00
|
||||
#define CS4270_MODE_DIV15 0x02
|
||||
#define CS4270_MODE_DIV2 0x04
|
||||
#define CS4270_MODE_DIV3 0x06
|
||||
#define CS4270_MODE_DIV4 0x08
|
||||
#define CS4270_MODE_POPGUARD 0x01
|
||||
#define CS4270_FORMAT_FREEZE_A 0x80
|
||||
#define CS4270_FORMAT_FREEZE_B 0x40
|
||||
#define CS4270_FORMAT_LOOPBACK 0x20
|
||||
#define CS4270_FORMAT_DAC_MASK 0x18
|
||||
#define CS4270_FORMAT_DAC_LJ 0x00
|
||||
#define CS4270_FORMAT_DAC_I2S 0x08
|
||||
#define CS4270_FORMAT_DAC_RJ16 0x18
|
||||
#define CS4270_FORMAT_DAC_RJ24 0x10
|
||||
#define CS4270_FORMAT_ADC_MASK 0x01
|
||||
#define CS4270_FORMAT_ADC_LJ 0x00
|
||||
#define CS4270_FORMAT_ADC_I2S 0x01
|
||||
#define CS4270_TRANS_ONE_VOL 0x80
|
||||
#define CS4270_TRANS_SOFT 0x40
|
||||
#define CS4270_TRANS_ZERO 0x20
|
||||
#define CS4270_TRANS_INV_ADC_A 0x08
|
||||
#define CS4270_TRANS_INV_ADC_B 0x10
|
||||
#define CS4270_TRANS_INV_DAC_A 0x02
|
||||
#define CS4270_TRANS_INV_DAC_B 0x04
|
||||
#define CS4270_TRANS_DEEMPH 0x01
|
||||
#define CS4270_MUTE_AUTO 0x20
|
||||
#define CS4270_MUTE_ADC_A 0x08
|
||||
#define CS4270_MUTE_ADC_B 0x10
|
||||
#define CS4270_MUTE_POLARITY 0x04
|
||||
#define CS4270_MUTE_DAC_A 0x01
|
||||
#define CS4270_MUTE_DAC_B 0x02
|
||||
|
||||
/* Power-on default values for the registers
|
||||
*
|
||||
* This array contains the power-on default values of the registers, with the
|
||||
* exception of the "CHIPID" register (01h). The lower four bits of that
|
||||
* register contain the hardware revision, so it is treated as volatile.
|
||||
*/
|
||||
static const struct reg_default cs4270_reg_defaults[] = {
|
||||
{ 2, 0x00 },
|
||||
{ 3, 0x30 },
|
||||
{ 4, 0x00 },
|
||||
{ 5, 0x60 },
|
||||
{ 6, 0x20 },
|
||||
{ 7, 0x00 },
|
||||
{ 8, 0x00 },
|
||||
};
|
||||
|
||||
static const char *supply_names[] = {
|
||||
"va", "vd", "vlc"
|
||||
};
|
||||
|
||||
/* Private data for the CS4270 */
|
||||
struct cs4270_private {
|
||||
struct regmap *regmap;
|
||||
unsigned int mclk; /* Input frequency of the MCLK pin */
|
||||
unsigned int mode; /* The mode (I2S or left-justified) */
|
||||
unsigned int slave_mode;
|
||||
unsigned int manual_mute;
|
||||
|
||||
/* power domain regulators */
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("AINL"),
|
||||
SND_SOC_DAPM_INPUT("AINR"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
|
||||
{ "Capture", NULL, "AINA" },
|
||||
{ "Capture", NULL, "AINB" },
|
||||
|
||||
{ "AOUTA", NULL, "Playback" },
|
||||
{ "AOUTB", NULL, "Playback" },
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cs4270_mode_ratios - clock ratio tables
|
||||
* @ratio: the ratio of MCLK to the sample rate
|
||||
* @speed_mode: the Speed Mode bits to set in the Mode Control register for
|
||||
* this ratio
|
||||
* @mclk: the Ratio Select bits to set in the Mode Control register for this
|
||||
* ratio
|
||||
*
|
||||
* The data for this chart is taken from Table 5 of the CS4270 reference
|
||||
* manual.
|
||||
*
|
||||
* This table is used to determine how to program the Mode Control register.
|
||||
* It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
|
||||
* rates the CS4270 currently supports.
|
||||
*
|
||||
* @speed_mode is the corresponding bit pattern to be written to the
|
||||
* MODE bits of the Mode Control Register
|
||||
*
|
||||
* @mclk is the corresponding bit pattern to be wirten to the MCLK bits of
|
||||
* the Mode Control Register.
|
||||
*
|
||||
* In situations where a single ratio is represented by multiple speed
|
||||
* modes, we favor the slowest speed. E.g, for a ratio of 128, we pick
|
||||
* double-speed instead of quad-speed. However, the CS4270 errata states
|
||||
* that divide-By-1.5 can cause failures, so we avoid that mode where
|
||||
* possible.
|
||||
*
|
||||
* Errata: There is an errata for the CS4270 where divide-by-1.5 does not
|
||||
* work if Vd is 3.3V. If this effects you, select the
|
||||
* CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
|
||||
* never select any sample rates that require divide-by-1.5.
|
||||
*/
|
||||
struct cs4270_mode_ratios {
|
||||
unsigned int ratio;
|
||||
u8 speed_mode;
|
||||
u8 mclk;
|
||||
};
|
||||
|
||||
static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
|
||||
{64, CS4270_MODE_4X, CS4270_MODE_DIV1},
|
||||
#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
|
||||
{96, CS4270_MODE_4X, CS4270_MODE_DIV15},
|
||||
#endif
|
||||
{128, CS4270_MODE_2X, CS4270_MODE_DIV1},
|
||||
{192, CS4270_MODE_4X, CS4270_MODE_DIV3},
|
||||
{256, CS4270_MODE_1X, CS4270_MODE_DIV1},
|
||||
{384, CS4270_MODE_2X, CS4270_MODE_DIV3},
|
||||
{512, CS4270_MODE_1X, CS4270_MODE_DIV2},
|
||||
{768, CS4270_MODE_1X, CS4270_MODE_DIV3},
|
||||
{1024, CS4270_MODE_1X, CS4270_MODE_DIV4}
|
||||
};
|
||||
|
||||
/* The number of MCLK/LRCK ratios supported by the CS4270 */
|
||||
#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)
|
||||
|
||||
static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
|
||||
}
|
||||
|
||||
static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* Unreadable registers are considered volatile */
|
||||
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
|
||||
return 1;
|
||||
|
||||
return reg == CS4270_CHIPID;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_set_dai_sysclk - determine the CS4270 samples rates.
|
||||
* @codec_dai: the codec DAI
|
||||
* @clk_id: the clock ID (ignored)
|
||||
* @freq: the MCLK input frequency
|
||||
* @dir: the clock direction (ignored)
|
||||
*
|
||||
* This function is used to tell the codec driver what the input MCLK
|
||||
* frequency is.
|
||||
*
|
||||
* The value of MCLK is used to determine which sample rates are supported
|
||||
* by the CS4270. The ratio of MCLK / Fs must be equal to one of nine
|
||||
* supported values - 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
|
||||
*
|
||||
* This function calculates the nine ratios and determines which ones match
|
||||
* a standard sample rate. If there's a match, then it is added to the list
|
||||
* of supported sample rates.
|
||||
*
|
||||
* This function must be called by the machine driver's 'startup' function,
|
||||
* otherwise the list of supported sample rates will not be available in
|
||||
* time for ALSA.
|
||||
*
|
||||
* For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
|
||||
* theoretically possible sample rates to be enabled. Call it again with a
|
||||
* proper value set one the external clock is set (most probably you would do
|
||||
* that from a machine's driver 'hw_param' hook.
|
||||
*/
|
||||
static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs4270->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_set_dai_fmt - configure the codec for the selected audio format
|
||||
* @codec_dai: the codec DAI
|
||||
* @format: a SND_SOC_DAIFMT_x value indicating the data format
|
||||
*
|
||||
* This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
|
||||
* codec accordingly.
|
||||
*
|
||||
* Currently, this function only supports SND_SOC_DAIFMT_I2S and
|
||||
* SND_SOC_DAIFMT_LEFT_J. The CS4270 codec also supports right-justified
|
||||
* data for playback only, but ASoC currently does not support different
|
||||
* formats for playback vs. record.
|
||||
*/
|
||||
static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* set DAI format */
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "invalid dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set master/slave audio interface */
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
cs4270->slave_mode = 1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
cs4270->slave_mode = 0;
|
||||
break;
|
||||
default:
|
||||
/* all other modes are unsupported by the hardware */
|
||||
dev_err(codec->dev, "Unknown master/slave configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_hw_params - program the CS4270 with the given hardware parameters.
|
||||
* @substream: the audio stream
|
||||
* @params: the hardware parameters to set
|
||||
* @dai: the SOC DAI (ignored)
|
||||
*
|
||||
* This function programs the hardware with the values provided.
|
||||
* Specifically, the sample rate and the data format.
|
||||
*
|
||||
* The .ops functions are used to provide board-specific data, like input
|
||||
* frequencies, to this driver. This function takes that information,
|
||||
* combines it with the hardware parameters provided, and programs the
|
||||
* hardware accordingly.
|
||||
*/
|
||||
static int cs4270_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
unsigned int rate;
|
||||
unsigned int ratio;
|
||||
int reg;
|
||||
|
||||
/* Figure out which MCLK/LRCK ratio to use */
|
||||
|
||||
rate = params_rate(params); /* Sampling rate, in Hz */
|
||||
ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */
|
||||
|
||||
for (i = 0; i < NUM_MCLK_RATIOS; i++) {
|
||||
if (cs4270_mode_ratios[i].ratio == ratio)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == NUM_MCLK_RATIOS) {
|
||||
/* We did not find a matching ratio */
|
||||
dev_err(codec->dev, "could not find matching ratio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set the sample rate */
|
||||
|
||||
reg = snd_soc_read(codec, CS4270_MODE);
|
||||
reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
|
||||
reg |= cs4270_mode_ratios[i].mclk;
|
||||
|
||||
if (cs4270->slave_mode)
|
||||
reg |= CS4270_MODE_SLAVE;
|
||||
else
|
||||
reg |= cs4270_mode_ratios[i].speed_mode;
|
||||
|
||||
ret = snd_soc_write(codec, CS4270_MODE, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the DAI format */
|
||||
|
||||
reg = snd_soc_read(codec, CS4270_FORMAT);
|
||||
reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);
|
||||
|
||||
switch (cs4270->mode) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unknown dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_write(codec, CS4270_FORMAT, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_dai_mute - enable/disable the CS4270 external mute
|
||||
* @dai: the SOC DAI
|
||||
* @mute: 0 = disable mute, 1 = enable mute
|
||||
*
|
||||
* This function toggles the mute bits in the MUTE register. The CS4270's
|
||||
* mute capability is intended for external muting circuitry, so if the
|
||||
* board does not have the MUTEA or MUTEB pins connected to such circuitry,
|
||||
* then this function will do nothing.
|
||||
*/
|
||||
static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg6;
|
||||
|
||||
reg6 = snd_soc_read(codec, CS4270_MUTE);
|
||||
|
||||
if (mute)
|
||||
reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
|
||||
else {
|
||||
reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
|
||||
reg6 |= cs4270->manual_mute;
|
||||
}
|
||||
|
||||
return snd_soc_write(codec, CS4270_MUTE, reg6);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_soc_put_mute - put callback for the 'Master Playback switch'
|
||||
* alsa control.
|
||||
* @kcontrol: mixer control
|
||||
* @ucontrol: control element information
|
||||
*
|
||||
* This function basically passes the arguments on to the generic
|
||||
* snd_soc_put_volsw() function and saves the mute information in
|
||||
* our private data structure. This is because we want to prevent
|
||||
* cs4270_dai_mute() neglecting the user's decision to manually
|
||||
* mute the codec's output.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int left = !ucontrol->value.integer.value[0];
|
||||
int right = !ucontrol->value.integer.value[1];
|
||||
|
||||
cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) |
|
||||
(right ? CS4270_MUTE_DAC_B : 0);
|
||||
|
||||
return snd_soc_put_volsw(kcontrol, ucontrol);
|
||||
}
|
||||
|
||||
/* A list of non-DAPM controls that the CS4270 supports */
|
||||
static const struct snd_kcontrol_new cs4270_snd_controls[] = {
|
||||
SOC_DOUBLE_R("Master Playback Volume",
|
||||
CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1),
|
||||
SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
|
||||
SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
|
||||
SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
|
||||
SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0),
|
||||
SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
|
||||
SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
|
||||
SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
|
||||
SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1,
|
||||
snd_soc_get_volsw, cs4270_soc_put_mute),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops cs4270_dai_ops = {
|
||||
.hw_params = cs4270_hw_params,
|
||||
.set_sysclk = cs4270_set_dai_sysclk,
|
||||
.set_fmt = cs4270_set_dai_fmt,
|
||||
.digital_mute = cs4270_dai_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs4270_dai = {
|
||||
.name = "cs4270-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 4000,
|
||||
.rate_max = 216000,
|
||||
.formats = CS4270_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 4000,
|
||||
.rate_max = 216000,
|
||||
.formats = CS4270_FORMATS,
|
||||
},
|
||||
.ops = &cs4270_dai_ops,
|
||||
};
|
||||
|
||||
/**
|
||||
* cs4270_probe - ASoC probe function
|
||||
* @pdev: platform device
|
||||
*
|
||||
* This function is called when ASoC has all the pieces it needs to
|
||||
* instantiate a sound driver.
|
||||
*/
|
||||
static int cs4270_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
/* Disable auto-mute. This feature appears to be buggy. In some
|
||||
* situations, auto-mute will not deactivate when it should, so we want
|
||||
* this feature disabled by default. An application (e.g. alsactl) can
|
||||
* re-enabled it by using the controls.
|
||||
*/
|
||||
ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable automatic volume control. The hardware enables, and it
|
||||
* causes volume change commands to be delayed, sometimes until after
|
||||
* playback has started. An application (e.g. alsactl) can
|
||||
* re-enabled it by using the controls.
|
||||
*/
|
||||
ret = snd_soc_update_bits(codec, CS4270_TRANS,
|
||||
CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "i2c write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_remove - ASoC remove function
|
||||
* @pdev: platform device
|
||||
*
|
||||
* This function is the counterpart to cs4270_probe().
|
||||
*/
|
||||
static int cs4270_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* This suspend/resume implementation can handle both - a simple standby
|
||||
* where the codec remains powered, and a full suspend, where the voltage
|
||||
* domain the codec is connected to is teared down and/or any other hardware
|
||||
* reset condition is asserted.
|
||||
*
|
||||
* The codec's own power saving features are enabled in the suspend callback,
|
||||
* and all registers are written back to the hardware when resuming.
|
||||
*/
|
||||
|
||||
static int cs4270_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg, ret;
|
||||
|
||||
reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
|
||||
ret = snd_soc_write(codec, CS4270_PWRCTL, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4270_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg, ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* In case the device was put to hard reset during sleep, we need to
|
||||
* wait 500ns here before any I2C communication. */
|
||||
ndelay(500);
|
||||
|
||||
/* first restore the entire register cache ... */
|
||||
regcache_sync(cs4270->regmap);
|
||||
|
||||
/* ... then disable the power-down bits */
|
||||
reg = snd_soc_read(codec, CS4270_PWRCTL);
|
||||
reg &= ~CS4270_PWRCTL_PDN_ALL;
|
||||
|
||||
return snd_soc_write(codec, CS4270_PWRCTL, reg);
|
||||
}
|
||||
#else
|
||||
#define cs4270_soc_suspend NULL
|
||||
#define cs4270_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* ASoC codec driver structure
|
||||
*/
|
||||
static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
|
||||
.probe = cs4270_probe,
|
||||
.remove = cs4270_remove,
|
||||
.suspend = cs4270_soc_suspend,
|
||||
.resume = cs4270_soc_resume,
|
||||
|
||||
.controls = cs4270_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs4270_snd_controls),
|
||||
.dapm_widgets = cs4270_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs4270_dapm_widgets),
|
||||
.dapm_routes = cs4270_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs4270_dapm_routes),
|
||||
};
|
||||
|
||||
/*
|
||||
* cs4270_of_match - the device tree bindings
|
||||
*/
|
||||
static const struct of_device_id cs4270_of_match[] = {
|
||||
{ .compatible = "cirrus,cs4270", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs4270_of_match);
|
||||
|
||||
static const struct regmap_config cs4270_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = CS4270_LASTREG,
|
||||
.reg_defaults = cs4270_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.readable_reg = cs4270_reg_is_readable,
|
||||
.volatile_reg = cs4270_reg_is_volatile,
|
||||
};
|
||||
|
||||
/**
|
||||
* cs4270_i2c_probe - initialize the I2C interface of the CS4270
|
||||
* @i2c_client: the I2C client object
|
||||
* @id: the I2C device ID (ignored)
|
||||
*
|
||||
* This function is called whenever the I2C subsystem finds a device that
|
||||
* matches the device ID given via a prior call to i2c_add_driver().
|
||||
*/
|
||||
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = i2c_client->dev.of_node;
|
||||
struct cs4270_private *cs4270;
|
||||
unsigned int val;
|
||||
int ret, i;
|
||||
|
||||
cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private),
|
||||
GFP_KERNEL);
|
||||
if (!cs4270)
|
||||
return -ENOMEM;
|
||||
|
||||
/* get the power supply regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
|
||||
cs4270->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&i2c_client->dev,
|
||||
ARRAY_SIZE(cs4270->supplies),
|
||||
cs4270->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* See if we have a way to bring the codec out of reset */
|
||||
if (np) {
|
||||
enum of_gpio_flags flags;
|
||||
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
|
||||
|
||||
if (gpio_is_valid(gpio)) {
|
||||
ret = devm_gpio_request_one(&i2c_client->dev, gpio,
|
||||
flags & OF_GPIO_ACTIVE_LOW ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
|
||||
"cs4270 reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
|
||||
if (IS_ERR(cs4270->regmap))
|
||||
return PTR_ERR(cs4270->regmap);
|
||||
|
||||
/* Verify that we have a CS4270 */
|
||||
ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
|
||||
i2c_client->addr);
|
||||
return ret;
|
||||
}
|
||||
/* The top four bits of the chip ID should be 1100. */
|
||||
if ((val & 0xF0) != 0xC0) {
|
||||
dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
|
||||
i2c_client->addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&i2c_client->dev, "found device at i2c address %X\n",
|
||||
i2c_client->addr);
|
||||
dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF);
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs4270);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_device_cs4270, &cs4270_dai, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cs4270_i2c_remove - remove an I2C device
|
||||
* @i2c_client: the I2C client object
|
||||
*
|
||||
* This function is the counterpart to cs4270_i2c_probe().
|
||||
*/
|
||||
static int cs4270_i2c_remove(struct i2c_client *i2c_client)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c_client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cs4270_id - I2C device IDs supported by this driver
|
||||
*/
|
||||
static const struct i2c_device_id cs4270_id[] = {
|
||||
{"cs4270", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4270_id);
|
||||
|
||||
/*
|
||||
* cs4270_i2c_driver - I2C device identification
|
||||
*
|
||||
* This structure tells the I2C subsystem how to identify and support a
|
||||
* given I2C device type.
|
||||
*/
|
||||
static struct i2c_driver cs4270_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4270",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = cs4270_of_match,
|
||||
},
|
||||
.id_table = cs4270_id,
|
||||
.probe = cs4270_i2c_probe,
|
||||
.remove = cs4270_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs4270_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
797
sound/soc/codecs/cs4271.c
Normal file
797
sound/soc/codecs/cs4271.c
Normal file
|
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
* CS4271 ASoC codec driver
|
||||
*
|
||||
* Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver support CS4271 codec being master or slave, working
|
||||
* in control port mode, connected either via SPI or I2C.
|
||||
* The data format accepted is I2S or left-justified.
|
||||
* DAPM support not implemented.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/cs4271.h>
|
||||
|
||||
#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000
|
||||
|
||||
/*
|
||||
* CS4271 registers
|
||||
*/
|
||||
#define CS4271_MODE1 0x01 /* Mode Control 1 */
|
||||
#define CS4271_DACCTL 0x02 /* DAC Control */
|
||||
#define CS4271_DACVOL 0x03 /* DAC Volume & Mixing Control */
|
||||
#define CS4271_VOLA 0x04 /* DAC Channel A Volume Control */
|
||||
#define CS4271_VOLB 0x05 /* DAC Channel B Volume Control */
|
||||
#define CS4271_ADCCTL 0x06 /* ADC Control */
|
||||
#define CS4271_MODE2 0x07 /* Mode Control 2 */
|
||||
#define CS4271_CHIPID 0x08 /* Chip ID */
|
||||
|
||||
#define CS4271_FIRSTREG CS4271_MODE1
|
||||
#define CS4271_LASTREG CS4271_MODE2
|
||||
#define CS4271_NR_REGS ((CS4271_LASTREG & 0xFF) + 1)
|
||||
|
||||
/* Bit masks for the CS4271 registers */
|
||||
#define CS4271_MODE1_MODE_MASK 0xC0
|
||||
#define CS4271_MODE1_MODE_1X 0x00
|
||||
#define CS4271_MODE1_MODE_2X 0x80
|
||||
#define CS4271_MODE1_MODE_4X 0xC0
|
||||
|
||||
#define CS4271_MODE1_DIV_MASK 0x30
|
||||
#define CS4271_MODE1_DIV_1 0x00
|
||||
#define CS4271_MODE1_DIV_15 0x10
|
||||
#define CS4271_MODE1_DIV_2 0x20
|
||||
#define CS4271_MODE1_DIV_3 0x30
|
||||
|
||||
#define CS4271_MODE1_MASTER 0x08
|
||||
|
||||
#define CS4271_MODE1_DAC_DIF_MASK 0x07
|
||||
#define CS4271_MODE1_DAC_DIF_LJ 0x00
|
||||
#define CS4271_MODE1_DAC_DIF_I2S 0x01
|
||||
#define CS4271_MODE1_DAC_DIF_RJ16 0x02
|
||||
#define CS4271_MODE1_DAC_DIF_RJ24 0x03
|
||||
#define CS4271_MODE1_DAC_DIF_RJ20 0x04
|
||||
#define CS4271_MODE1_DAC_DIF_RJ18 0x05
|
||||
|
||||
#define CS4271_DACCTL_AMUTE 0x80
|
||||
#define CS4271_DACCTL_IF_SLOW 0x40
|
||||
|
||||
#define CS4271_DACCTL_DEM_MASK 0x30
|
||||
#define CS4271_DACCTL_DEM_DIS 0x00
|
||||
#define CS4271_DACCTL_DEM_441 0x10
|
||||
#define CS4271_DACCTL_DEM_48 0x20
|
||||
#define CS4271_DACCTL_DEM_32 0x30
|
||||
|
||||
#define CS4271_DACCTL_SVRU 0x08
|
||||
#define CS4271_DACCTL_SRD 0x04
|
||||
#define CS4271_DACCTL_INVA 0x02
|
||||
#define CS4271_DACCTL_INVB 0x01
|
||||
|
||||
#define CS4271_DACVOL_BEQUA 0x40
|
||||
#define CS4271_DACVOL_SOFT 0x20
|
||||
#define CS4271_DACVOL_ZEROC 0x10
|
||||
|
||||
#define CS4271_DACVOL_ATAPI_MASK 0x0F
|
||||
#define CS4271_DACVOL_ATAPI_M_M 0x00
|
||||
#define CS4271_DACVOL_ATAPI_M_BR 0x01
|
||||
#define CS4271_DACVOL_ATAPI_M_BL 0x02
|
||||
#define CS4271_DACVOL_ATAPI_M_BLR2 0x03
|
||||
#define CS4271_DACVOL_ATAPI_AR_M 0x04
|
||||
#define CS4271_DACVOL_ATAPI_AR_BR 0x05
|
||||
#define CS4271_DACVOL_ATAPI_AR_BL 0x06
|
||||
#define CS4271_DACVOL_ATAPI_AR_BLR2 0x07
|
||||
#define CS4271_DACVOL_ATAPI_AL_M 0x08
|
||||
#define CS4271_DACVOL_ATAPI_AL_BR 0x09
|
||||
#define CS4271_DACVOL_ATAPI_AL_BL 0x0A
|
||||
#define CS4271_DACVOL_ATAPI_AL_BLR2 0x0B
|
||||
#define CS4271_DACVOL_ATAPI_ALR2_M 0x0C
|
||||
#define CS4271_DACVOL_ATAPI_ALR2_BR 0x0D
|
||||
#define CS4271_DACVOL_ATAPI_ALR2_BL 0x0E
|
||||
#define CS4271_DACVOL_ATAPI_ALR2_BLR2 0x0F
|
||||
|
||||
#define CS4271_VOLA_MUTE 0x80
|
||||
#define CS4271_VOLA_VOL_MASK 0x7F
|
||||
#define CS4271_VOLB_MUTE 0x80
|
||||
#define CS4271_VOLB_VOL_MASK 0x7F
|
||||
|
||||
#define CS4271_ADCCTL_DITHER16 0x20
|
||||
|
||||
#define CS4271_ADCCTL_ADC_DIF_MASK 0x10
|
||||
#define CS4271_ADCCTL_ADC_DIF_LJ 0x00
|
||||
#define CS4271_ADCCTL_ADC_DIF_I2S 0x10
|
||||
|
||||
#define CS4271_ADCCTL_MUTEA 0x08
|
||||
#define CS4271_ADCCTL_MUTEB 0x04
|
||||
#define CS4271_ADCCTL_HPFDA 0x02
|
||||
#define CS4271_ADCCTL_HPFDB 0x01
|
||||
|
||||
#define CS4271_MODE2_LOOP 0x10
|
||||
#define CS4271_MODE2_MUTECAEQUB 0x08
|
||||
#define CS4271_MODE2_FREEZE 0x04
|
||||
#define CS4271_MODE2_CPEN 0x02
|
||||
#define CS4271_MODE2_PDN 0x01
|
||||
|
||||
#define CS4271_CHIPID_PART_MASK 0xF0
|
||||
#define CS4271_CHIPID_REV_MASK 0x0F
|
||||
|
||||
/*
|
||||
* Default CS4271 power-up configuration
|
||||
* Array contains non-existing in hw register at address 0
|
||||
* Array do not include Chip ID, as codec driver does not use
|
||||
* registers read operations at all
|
||||
*/
|
||||
static const struct reg_default cs4271_reg_defaults[] = {
|
||||
{ CS4271_MODE1, 0, },
|
||||
{ CS4271_DACCTL, CS4271_DACCTL_AMUTE, },
|
||||
{ CS4271_DACVOL, CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },
|
||||
{ CS4271_VOLA, 0, },
|
||||
{ CS4271_VOLB, 0, },
|
||||
{ CS4271_ADCCTL, 0, },
|
||||
{ CS4271_MODE2, 0, },
|
||||
};
|
||||
|
||||
static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg == CS4271_CHIPID;
|
||||
}
|
||||
|
||||
struct cs4271_private {
|
||||
unsigned int mclk;
|
||||
bool master;
|
||||
bool deemph;
|
||||
struct regmap *regmap;
|
||||
/* Current sample rate for de-emphasis control */
|
||||
int rate;
|
||||
/* GPIO driving Reset pin, if any */
|
||||
int gpio_nreset;
|
||||
/* GPIO that disable serial bus, if any */
|
||||
int gpio_disable;
|
||||
/* enable soft reset workaround */
|
||||
bool enable_soft_reset;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("AINA"),
|
||||
SND_SOC_DAPM_INPUT("AINB"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUTA+"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTA-"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTB+"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTB-"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
|
||||
{ "Capture", NULL, "AINA" },
|
||||
{ "Capture", NULL, "AINB" },
|
||||
|
||||
{ "AOUTA+", NULL, "Playback" },
|
||||
{ "AOUTA-", NULL, "Playback" },
|
||||
{ "AOUTB+", NULL, "Playback" },
|
||||
{ "AOUTB-", NULL, "Playback" },
|
||||
};
|
||||
|
||||
/*
|
||||
* @freq is the desired MCLK rate
|
||||
* MCLK rate should (c) be the sample rate, multiplied by one of the
|
||||
* ratios listed in cs4271_mclk_fs_ratios table
|
||||
*/
|
||||
static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs4271->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
cs4271->master = 0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
cs4271->master = 1;
|
||||
val |= CS4271_MODE1_MASTER;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val |= CS4271_MODE1_DAC_DIF_LJ;
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
|
||||
CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val |= CS4271_MODE1_DAC_DIF_I2S;
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
|
||||
CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
|
||||
CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_deemph[] = {0, 44100, 48000, 32000};
|
||||
|
||||
static int cs4271_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
int val = CS4271_DACCTL_DEM_DIS;
|
||||
|
||||
if (cs4271->deemph) {
|
||||
/* Find closest de-emphasis freq */
|
||||
val = 1;
|
||||
for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++)
|
||||
if (abs(cs4271_deemph[i] - cs4271->rate) <
|
||||
abs(cs4271_deemph[val] - cs4271->rate))
|
||||
val = i;
|
||||
val <<= 4;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,
|
||||
CS4271_DACCTL_DEM_MASK, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = cs4271->deemph;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs4271->deemph = ucontrol->value.integer.value[0];
|
||||
return cs4271_set_deemph(codec);
|
||||
}
|
||||
|
||||
struct cs4271_clk_cfg {
|
||||
bool master; /* codec mode */
|
||||
u8 speed_mode; /* codec speed mode: 1x, 2x, 4x */
|
||||
unsigned short ratio; /* MCLK / sample rate */
|
||||
u8 ratio_mask; /* ratio bit mask for Master mode */
|
||||
};
|
||||
|
||||
static struct cs4271_clk_cfg cs4271_clk_tab[] = {
|
||||
{1, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1},
|
||||
{1, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_15},
|
||||
{1, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_2},
|
||||
{1, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_3},
|
||||
{1, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1},
|
||||
{1, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_15},
|
||||
{1, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_2},
|
||||
{1, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_3},
|
||||
{1, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1},
|
||||
{1, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_15},
|
||||
{1, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_2},
|
||||
{1, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_3},
|
||||
{0, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_2},
|
||||
{0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2},
|
||||
{0, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_2},
|
||||
{0, CS4271_MODE1_MODE_2X, 512, CS4271_MODE1_DIV_2},
|
||||
{0, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_1},
|
||||
{0, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_2},
|
||||
{0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2},
|
||||
};
|
||||
|
||||
#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
|
||||
|
||||
static int cs4271_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
unsigned int ratio, val;
|
||||
|
||||
if (cs4271->enable_soft_reset) {
|
||||
/*
|
||||
* Put the codec in soft reset and back again in case it's not
|
||||
* currently streaming data. This way of bringing the codec in
|
||||
* sync to the current clocks is not explicitly documented in
|
||||
* the data sheet, but it seems to work fine, and in contrast
|
||||
* to a read hardware reset, we don't have to sync back all
|
||||
* registers every time.
|
||||
*/
|
||||
|
||||
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
!dai->capture_active) ||
|
||||
(substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
|
||||
!dai->playback_active)) {
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN,
|
||||
CS4271_MODE2_PDN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
cs4271->rate = params_rate(params);
|
||||
|
||||
/* Configure DAC */
|
||||
if (cs4271->rate < 50000)
|
||||
val = CS4271_MODE1_MODE_1X;
|
||||
else if (cs4271->rate < 100000)
|
||||
val = CS4271_MODE1_MODE_2X;
|
||||
else
|
||||
val = CS4271_MODE1_MODE_4X;
|
||||
|
||||
ratio = cs4271->mclk / cs4271->rate;
|
||||
for (i = 0; i < CS4171_NR_RATIOS; i++)
|
||||
if ((cs4271_clk_tab[i].master == cs4271->master) &&
|
||||
(cs4271_clk_tab[i].speed_mode == val) &&
|
||||
(cs4271_clk_tab[i].ratio == ratio))
|
||||
break;
|
||||
|
||||
if (i == CS4171_NR_RATIOS) {
|
||||
dev_err(codec->dev, "Invalid sample rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val |= cs4271_clk_tab[i].ratio_mask;
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
|
||||
CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return cs4271_set_deemph(codec);
|
||||
}
|
||||
|
||||
static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
int val_a = 0;
|
||||
int val_b = 0;
|
||||
|
||||
if (stream != SNDRV_PCM_STREAM_PLAYBACK)
|
||||
return 0;
|
||||
|
||||
if (mute) {
|
||||
val_a = CS4271_VOLA_MUTE;
|
||||
val_b = CS4271_VOLB_MUTE;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,
|
||||
CS4271_VOLA_MUTE, val_a);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,
|
||||
CS4271_VOLB_MUTE, val_b);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CS4271 controls */
|
||||
static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0);
|
||||
|
||||
static const struct snd_kcontrol_new cs4271_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB,
|
||||
0, 0x7F, 1, cs4271_dac_tlv),
|
||||
SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),
|
||||
SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),
|
||||
SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),
|
||||
SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
|
||||
cs4271_get_deemph, cs4271_put_deemph),
|
||||
SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),
|
||||
SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),
|
||||
SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),
|
||||
SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),
|
||||
SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),
|
||||
SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),
|
||||
SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),
|
||||
SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),
|
||||
SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),
|
||||
SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB,
|
||||
7, 1, 1),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops cs4271_dai_ops = {
|
||||
.hw_params = cs4271_hw_params,
|
||||
.set_sysclk = cs4271_set_dai_sysclk,
|
||||
.set_fmt = cs4271_set_dai_fmt,
|
||||
.mute_stream = cs4271_mute_stream,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs4271_dai = {
|
||||
.name = "cs4271-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = CS4271_PCM_RATES,
|
||||
.formats = CS4271_PCM_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = CS4271_PCM_RATES,
|
||||
.formats = CS4271_PCM_FORMATS,
|
||||
},
|
||||
.ops = &cs4271_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int cs4271_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Set power-down bit */
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN, CS4271_MODE2_PDN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Restore codec state */
|
||||
ret = regcache_sync(cs4271->regmap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* then disable the power-down bit */
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define cs4271_soc_suspend NULL
|
||||
#define cs4271_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cs4271_dt_ids[] = {
|
||||
{ .compatible = "cirrus,cs4271", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
|
||||
#endif
|
||||
|
||||
static int cs4271_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
|
||||
int ret;
|
||||
bool amutec_eq_bmutec = false;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (of_match_device(cs4271_dt_ids, codec->dev)) {
|
||||
if (of_get_property(codec->dev->of_node,
|
||||
"cirrus,amutec-eq-bmutec", NULL))
|
||||
amutec_eq_bmutec = true;
|
||||
|
||||
if (of_get_property(codec->dev->of_node,
|
||||
"cirrus,enable-soft-reset", NULL))
|
||||
cs4271->enable_soft_reset = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cs4271plat) {
|
||||
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
|
||||
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(cs4271->gpio_nreset)) {
|
||||
/* Reset codec */
|
||||
gpio_direction_output(cs4271->gpio_nreset, 0);
|
||||
mdelay(1);
|
||||
gpio_set_value(cs4271->gpio_nreset, 1);
|
||||
/* Give the codec time to wake up */
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
|
||||
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Power-up sequence requires 85 uS */
|
||||
udelay(85);
|
||||
|
||||
if (amutec_eq_bmutec)
|
||||
regmap_update_bits(cs4271->regmap, CS4271_MODE2,
|
||||
CS4271_MODE2_MUTECAEQUB,
|
||||
CS4271_MODE2_MUTECAEQUB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(cs4271->gpio_nreset))
|
||||
/* Set codec to the reset state */
|
||||
gpio_set_value(cs4271->gpio_nreset, 0);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
|
||||
.probe = cs4271_probe,
|
||||
.remove = cs4271_remove,
|
||||
.suspend = cs4271_soc_suspend,
|
||||
.resume = cs4271_soc_resume,
|
||||
|
||||
.controls = cs4271_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs4271_snd_controls),
|
||||
.dapm_widgets = cs4271_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs4271_dapm_widgets),
|
||||
.dapm_routes = cs4271_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes),
|
||||
};
|
||||
|
||||
static int cs4271_common_probe(struct device *dev,
|
||||
struct cs4271_private **c)
|
||||
{
|
||||
struct cs4271_platform_data *cs4271plat = dev->platform_data;
|
||||
struct cs4271_private *cs4271;
|
||||
|
||||
cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
|
||||
if (!cs4271)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_match_device(cs4271_dt_ids, dev))
|
||||
cs4271->gpio_nreset =
|
||||
of_get_named_gpio(dev->of_node, "reset-gpio", 0);
|
||||
|
||||
if (cs4271plat)
|
||||
cs4271->gpio_nreset = cs4271plat->gpio_nreset;
|
||||
|
||||
if (gpio_is_valid(cs4271->gpio_nreset)) {
|
||||
int ret;
|
||||
|
||||
ret = devm_gpio_request(dev, cs4271->gpio_nreset,
|
||||
"CS4271 Reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*c = cs4271;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
|
||||
static const struct regmap_config cs4271_spi_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = CS4271_LASTREG,
|
||||
.read_flag_mask = 0x21,
|
||||
.write_flag_mask = 0x20,
|
||||
|
||||
.reg_defaults = cs4271_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.volatile_reg = cs4271_volatile_reg,
|
||||
};
|
||||
|
||||
static int cs4271_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct cs4271_private *cs4271;
|
||||
int ret;
|
||||
|
||||
ret = cs4271_common_probe(&spi->dev, &cs4271);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, cs4271);
|
||||
cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
|
||||
if (IS_ERR(cs4271->regmap))
|
||||
return PTR_ERR(cs4271->regmap);
|
||||
|
||||
return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
|
||||
&cs4271_dai, 1);
|
||||
}
|
||||
|
||||
static int cs4271_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver cs4271_spi_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.probe = cs4271_spi_probe,
|
||||
.remove = cs4271_spi_remove,
|
||||
};
|
||||
#endif /* defined(CONFIG_SPI_MASTER) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
static const struct i2c_device_id cs4271_i2c_id[] = {
|
||||
{"cs4271", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
|
||||
|
||||
static const struct regmap_config cs4271_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = CS4271_LASTREG,
|
||||
|
||||
.reg_defaults = cs4271_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.volatile_reg = cs4271_volatile_reg,
|
||||
};
|
||||
|
||||
static int cs4271_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cs4271_private *cs4271;
|
||||
int ret;
|
||||
|
||||
ret = cs4271_common_probe(&client->dev, &cs4271);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, cs4271);
|
||||
cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
|
||||
if (IS_ERR(cs4271->regmap))
|
||||
return PTR_ERR(cs4271->regmap);
|
||||
|
||||
return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
|
||||
&cs4271_dai, 1);
|
||||
}
|
||||
|
||||
static int cs4271_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver cs4271_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.id_table = cs4271_i2c_id,
|
||||
.probe = cs4271_i2c_probe,
|
||||
.remove = cs4271_i2c_remove,
|
||||
};
|
||||
#endif /* IS_ENABLED(CONFIG_I2C) */
|
||||
|
||||
/*
|
||||
* We only register our serial bus driver here without
|
||||
* assignment to particular chip. So if any of the below
|
||||
* fails, there is some problem with I2C or SPI subsystem.
|
||||
* In most cases this module will be compiled with support
|
||||
* of only one serial bus.
|
||||
*/
|
||||
static int __init cs4271_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
ret = i2c_add_driver(&cs4271_i2c_driver);
|
||||
if (ret) {
|
||||
pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&cs4271_spi_driver);
|
||||
if (ret) {
|
||||
pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(cs4271_modinit);
|
||||
|
||||
static void __exit cs4271_modexit(void)
|
||||
{
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&cs4271_spi_driver);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
i2c_del_driver(&cs4271_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(cs4271_modexit);
|
||||
|
||||
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
60
sound/soc/codecs/cs42l51-i2c.c
Normal file
60
sound/soc/codecs/cs42l51-i2c.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* cs42l56.c -- CS42L51 ALSA SoC I2C audio driver
|
||||
*
|
||||
* Copyright 2014 CirrusLogic, Inc.
|
||||
*
|
||||
* Author: Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "cs42l51.h"
|
||||
|
||||
static struct i2c_device_id cs42l51_i2c_id[] = {
|
||||
{"cs42l51", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
|
||||
|
||||
static int cs42l51_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = cs42l51_regmap;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 8;
|
||||
|
||||
return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
|
||||
}
|
||||
|
||||
static int cs42l51_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver cs42l51_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42l51",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = cs42l51_of_match,
|
||||
},
|
||||
.probe = cs42l51_i2c_probe,
|
||||
.remove = cs42l51_i2c_remove,
|
||||
.id_table = cs42l51_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs42l51_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver");
|
||||
MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
570
sound/soc/codecs/cs42l51.c
Normal file
570
sound/soc/codecs/cs42l51.c
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* cs42l51.c
|
||||
*
|
||||
* ASoC Driver for Cirrus Logic CS42L51 codecs
|
||||
*
|
||||
* Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
|
||||
*
|
||||
* Based on cs4270.c - Copyright (c) Freescale Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* For now:
|
||||
* - Only I2C is support. Not SPI
|
||||
* - master mode *NOT* supported
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "cs42l51.h"
|
||||
|
||||
enum master_slave_mode {
|
||||
MODE_SLAVE,
|
||||
MODE_SLAVE_AUTO,
|
||||
MODE_MASTER,
|
||||
};
|
||||
|
||||
struct cs42l51_private {
|
||||
unsigned int mclk;
|
||||
unsigned int audio_mode; /* The mode (I2S or left-justified) */
|
||||
enum master_slave_mode func;
|
||||
};
|
||||
|
||||
#define CS42L51_FORMATS ( \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
|
||||
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
|
||||
|
||||
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
|
||||
|
||||
switch (value) {
|
||||
default:
|
||||
case 0:
|
||||
ucontrol->value.integer.value[0] = 0;
|
||||
break;
|
||||
/* same value : (L+R)/2 and (R+L)/2 */
|
||||
case 1:
|
||||
case 2:
|
||||
ucontrol->value.integer.value[0] = 1;
|
||||
break;
|
||||
case 3:
|
||||
ucontrol->value.integer.value[0] = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHAN_MIX_NORMAL 0x00
|
||||
#define CHAN_MIX_BOTH 0x55
|
||||
#define CHAN_MIX_SWAP 0xFF
|
||||
|
||||
static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
unsigned char val;
|
||||
|
||||
switch (ucontrol->value.integer.value[0]) {
|
||||
default:
|
||||
case 0:
|
||||
val = CHAN_MIX_NORMAL;
|
||||
break;
|
||||
case 1:
|
||||
val = CHAN_MIX_BOTH;
|
||||
break;
|
||||
case 2:
|
||||
val = CHAN_MIX_SWAP;
|
||||
break;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, CS42L51_PCM_MIXER, val);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
|
||||
static const char *chan_mix[] = {
|
||||
"L R",
|
||||
"L+R",
|
||||
"R L",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
|
||||
|
||||
static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
|
||||
SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
|
||||
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
|
||||
0, 0x19, 0x7F, adc_pcm_tlv),
|
||||
SOC_DOUBLE_R("PCM Playback Switch",
|
||||
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
|
||||
SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
|
||||
CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
|
||||
0, 0x34, 0xE4, aout_tlv),
|
||||
SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
|
||||
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
|
||||
0, 0x19, 0x7F, adc_pcm_tlv),
|
||||
SOC_DOUBLE_R("ADC Mixer Switch",
|
||||
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
|
||||
SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
|
||||
SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
|
||||
SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
|
||||
SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
|
||||
SOC_DOUBLE_TLV("Mic Boost Volume",
|
||||
CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
|
||||
SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
|
||||
SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
|
||||
SOC_ENUM_EXT("PCM channel mixer",
|
||||
cs42l51_chan_mix,
|
||||
cs42l51_get_chan_mix, cs42l51_set_chan_mix),
|
||||
};
|
||||
|
||||
/*
|
||||
* to power down, one must:
|
||||
* 1.) Enable the PDN bit
|
||||
* 2.) enable power-down for the select channels
|
||||
* 3.) disable the PDN bit.
|
||||
*/
|
||||
static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
|
||||
CS42L51_POWER_CTL1_PDN,
|
||||
CS42L51_POWER_CTL1_PDN);
|
||||
break;
|
||||
default:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
|
||||
CS42L51_POWER_CTL1_PDN, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *cs42l51_dac_names[] = {"Direct PCM",
|
||||
"DSP PCM", "ADC"};
|
||||
static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
|
||||
CS42L51_DAC_CTL, 6, cs42l51_dac_names);
|
||||
static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
|
||||
SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
|
||||
|
||||
static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
|
||||
"MIC Left", "MIC+preamp Left"};
|
||||
static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
|
||||
CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
|
||||
static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
|
||||
SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
|
||||
|
||||
static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
|
||||
"MIC Right", "MIC+preamp Right"};
|
||||
static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
|
||||
CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
|
||||
static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
|
||||
SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
|
||||
SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
|
||||
CS42L51_POWER_CTL1, 1, 1,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
|
||||
CS42L51_POWER_CTL1, 2, 1,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
|
||||
CS42L51_POWER_CTL1, 5, 1,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
|
||||
CS42L51_POWER_CTL1, 6, 1,
|
||||
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
|
||||
|
||||
/* analog/mic */
|
||||
SND_SOC_DAPM_INPUT("AIN1L"),
|
||||
SND_SOC_DAPM_INPUT("AIN1R"),
|
||||
SND_SOC_DAPM_INPUT("AIN2L"),
|
||||
SND_SOC_DAPM_INPUT("AIN2R"),
|
||||
SND_SOC_DAPM_INPUT("MICL"),
|
||||
SND_SOC_DAPM_INPUT("MICR"),
|
||||
|
||||
SND_SOC_DAPM_MIXER("Mic Preamp Left",
|
||||
CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("Mic Preamp Right",
|
||||
CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
|
||||
|
||||
/* HP */
|
||||
SND_SOC_DAPM_OUTPUT("HPL"),
|
||||
SND_SOC_DAPM_OUTPUT("HPR"),
|
||||
|
||||
/* mux */
|
||||
SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
|
||||
&cs42l51_dac_mux_controls),
|
||||
SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
|
||||
&cs42l51_adcl_mux_controls),
|
||||
SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
|
||||
&cs42l51_adcr_mux_controls),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42l51_routes[] = {
|
||||
{"HPL", NULL, "Left DAC"},
|
||||
{"HPR", NULL, "Right DAC"},
|
||||
|
||||
{"Left ADC", NULL, "Left PGA"},
|
||||
{"Right ADC", NULL, "Right PGA"},
|
||||
|
||||
{"Mic Preamp Left", NULL, "MICL"},
|
||||
{"Mic Preamp Right", NULL, "MICR"},
|
||||
|
||||
{"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
|
||||
{"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
|
||||
{"PGA-ADC Mux Left", "MIC Left", "MICL" },
|
||||
{"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
|
||||
{"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
|
||||
{"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
|
||||
{"PGA-ADC Mux Right", "MIC Right", "MICR" },
|
||||
{"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
|
||||
|
||||
{"Left PGA", NULL, "PGA-ADC Mux Left"},
|
||||
{"Right PGA", NULL, "PGA-ADC Mux Right"},
|
||||
};
|
||||
|
||||
static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
cs42l51->func = MODE_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
cs42l51->func = MODE_SLAVE_AUTO;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Unknown master/slave configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cs42l51_ratios {
|
||||
unsigned int ratio;
|
||||
unsigned char speed_mode;
|
||||
unsigned char mclk;
|
||||
};
|
||||
|
||||
static struct cs42l51_ratios slave_ratios[] = {
|
||||
{ 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
|
||||
{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
|
||||
{ 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
|
||||
{ 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
|
||||
{ 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
|
||||
{ 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
|
||||
{ 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
|
||||
{ 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
|
||||
{ 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
|
||||
{ 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
|
||||
{ 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
|
||||
};
|
||||
|
||||
static struct cs42l51_ratios slave_auto_ratios[] = {
|
||||
{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
|
||||
{ 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
|
||||
{ 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
|
||||
{ 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
|
||||
{ 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
|
||||
{ 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
|
||||
{ 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
|
||||
{ 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
|
||||
};
|
||||
|
||||
static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs42l51->mclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l51_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
unsigned int i;
|
||||
unsigned int rate;
|
||||
unsigned int ratio;
|
||||
struct cs42l51_ratios *ratios = NULL;
|
||||
int nr_ratios = 0;
|
||||
int intf_ctl, power_ctl, fmt;
|
||||
|
||||
switch (cs42l51->func) {
|
||||
case MODE_MASTER:
|
||||
return -EINVAL;
|
||||
case MODE_SLAVE:
|
||||
ratios = slave_ratios;
|
||||
nr_ratios = ARRAY_SIZE(slave_ratios);
|
||||
break;
|
||||
case MODE_SLAVE_AUTO:
|
||||
ratios = slave_auto_ratios;
|
||||
nr_ratios = ARRAY_SIZE(slave_auto_ratios);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Figure out which MCLK/LRCK ratio to use */
|
||||
rate = params_rate(params); /* Sampling rate, in Hz */
|
||||
ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
|
||||
for (i = 0; i < nr_ratios; i++) {
|
||||
if (ratios[i].ratio == ratio)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == nr_ratios) {
|
||||
/* We did not find a matching ratio */
|
||||
dev_err(codec->dev, "could not find matching ratio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
|
||||
power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
|
||||
|
||||
intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
|
||||
| CS42L51_INTF_CTL_DAC_FORMAT(7));
|
||||
power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
|
||||
| CS42L51_MIC_POWER_CTL_MCLK_DIV2);
|
||||
|
||||
switch (cs42l51->func) {
|
||||
case MODE_MASTER:
|
||||
intf_ctl |= CS42L51_INTF_CTL_MASTER;
|
||||
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
|
||||
break;
|
||||
case MODE_SLAVE:
|
||||
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
|
||||
break;
|
||||
case MODE_SLAVE_AUTO:
|
||||
power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cs42l51->audio_mode) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
|
||||
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
fmt = CS42L51_DAC_DIF_RJ16;
|
||||
break;
|
||||
case 18:
|
||||
fmt = CS42L51_DAC_DIF_RJ18;
|
||||
break;
|
||||
case 20:
|
||||
fmt = CS42L51_DAC_DIF_RJ20;
|
||||
break;
|
||||
case 24:
|
||||
fmt = CS42L51_DAC_DIF_RJ24;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unknown format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unknown format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ratios[i].mclk)
|
||||
power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
|
||||
|
||||
ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int reg;
|
||||
int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
|
||||
|
||||
reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
|
||||
|
||||
if (mute)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
|
||||
return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops cs42l51_dai_ops = {
|
||||
.hw_params = cs42l51_hw_params,
|
||||
.set_sysclk = cs42l51_set_dai_sysclk,
|
||||
.set_fmt = cs42l51_set_dai_fmt,
|
||||
.digital_mute = cs42l51_dai_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs42l51_dai = {
|
||||
.name = "cs42l51-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = CS42L51_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = CS42L51_FORMATS,
|
||||
},
|
||||
.ops = &cs42l51_dai_ops,
|
||||
};
|
||||
|
||||
static int cs42l51_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret, reg;
|
||||
|
||||
/*
|
||||
* DAC configuration
|
||||
* - Use signal processor
|
||||
* - auto mute
|
||||
* - vol changes immediate
|
||||
* - no de-emphasize
|
||||
*/
|
||||
reg = CS42L51_DAC_CTL_DATA_SEL(1)
|
||||
| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
|
||||
ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
|
||||
.probe = cs42l51_codec_probe,
|
||||
|
||||
.controls = cs42l51_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
|
||||
.dapm_widgets = cs42l51_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
|
||||
.dapm_routes = cs42l51_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
|
||||
};
|
||||
|
||||
const struct regmap_config cs42l51_regmap = {
|
||||
.max_register = CS42L51_CHARGE_FREQ,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42l51_regmap);
|
||||
|
||||
int cs42l51_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct cs42l51_private *cs42l51;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
|
||||
GFP_KERNEL);
|
||||
if (!cs42l51)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, cs42l51);
|
||||
|
||||
/* Verify that we have a CS42L51 */
|
||||
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read I2C\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
|
||||
(val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
|
||||
dev_err(dev, "Invalid chip id: %x\n", val);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
|
||||
val & CS42L51_CHIP_REV_MASK);
|
||||
|
||||
ret = snd_soc_register_codec(dev,
|
||||
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs42l51_probe);
|
||||
|
||||
const struct of_device_id cs42l51_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42l51", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42l51_of_match);
|
||||
EXPORT_SYMBOL_GPL(cs42l51_of_match);
|
||||
|
||||
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
168
sound/soc/codecs/cs42l51.h
Normal file
168
sound/soc/codecs/cs42l51.h
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* cs42l51.h
|
||||
*
|
||||
* ASoC Driver for Cirrus Logic CS42L51 codecs
|
||||
*
|
||||
* Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _CS42L51_H
|
||||
#define _CS42L51_H
|
||||
|
||||
struct device;
|
||||
|
||||
extern const struct regmap_config cs42l51_regmap;
|
||||
int cs42l51_probe(struct device *dev, struct regmap *regmap);
|
||||
extern const struct of_device_id cs42l51_of_match[];
|
||||
|
||||
#define CS42L51_CHIP_ID 0x1B
|
||||
#define CS42L51_CHIP_REV_A 0x00
|
||||
#define CS42L51_CHIP_REV_B 0x01
|
||||
#define CS42L51_CHIP_REV_MASK 0x07
|
||||
|
||||
#define CS42L51_CHIP_REV_ID 0x01
|
||||
#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
|
||||
|
||||
#define CS42L51_POWER_CTL1 0x02
|
||||
#define CS42L51_POWER_CTL1_PDN_DACB (1<<6)
|
||||
#define CS42L51_POWER_CTL1_PDN_DACA (1<<5)
|
||||
#define CS42L51_POWER_CTL1_PDN_PGAB (1<<4)
|
||||
#define CS42L51_POWER_CTL1_PDN_PGAA (1<<3)
|
||||
#define CS42L51_POWER_CTL1_PDN_ADCB (1<<2)
|
||||
#define CS42L51_POWER_CTL1_PDN_ADCA (1<<1)
|
||||
#define CS42L51_POWER_CTL1_PDN (1<<0)
|
||||
|
||||
#define CS42L51_MIC_POWER_CTL 0x03
|
||||
#define CS42L51_MIC_POWER_CTL_AUTO (1<<7)
|
||||
#define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5)
|
||||
#define CS42L51_QSM_MODE 3
|
||||
#define CS42L51_HSM_MODE 2
|
||||
#define CS42L51_SSM_MODE 1
|
||||
#define CS42L51_DSM_MODE 0
|
||||
#define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4)
|
||||
#define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3)
|
||||
#define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2)
|
||||
#define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1)
|
||||
#define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0)
|
||||
|
||||
#define CS42L51_INTF_CTL 0x04
|
||||
#define CS42L51_INTF_CTL_LOOPBACK (1<<7)
|
||||
#define CS42L51_INTF_CTL_MASTER (1<<6)
|
||||
#define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3)
|
||||
#define CS42L51_DAC_DIF_LJ24 0x00
|
||||
#define CS42L51_DAC_DIF_I2S 0x01
|
||||
#define CS42L51_DAC_DIF_RJ24 0x02
|
||||
#define CS42L51_DAC_DIF_RJ20 0x03
|
||||
#define CS42L51_DAC_DIF_RJ18 0x04
|
||||
#define CS42L51_DAC_DIF_RJ16 0x05
|
||||
#define CS42L51_INTF_CTL_ADC_I2S (1<<2)
|
||||
#define CS42L51_INTF_CTL_DIGMIX (1<<1)
|
||||
#define CS42L51_INTF_CTL_MICMIX (1<<0)
|
||||
|
||||
#define CS42L51_MIC_CTL 0x05
|
||||
#define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7)
|
||||
#define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6)
|
||||
#define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5)
|
||||
#define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4)
|
||||
#define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2)
|
||||
#define CS42L51_MIC_CTL_MICB_BOOST (1<<1)
|
||||
#define CS42L51_MIC_CTL_MICA_BOOST (1<<0)
|
||||
|
||||
#define CS42L51_ADC_CTL 0x06
|
||||
#define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7)
|
||||
#define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6)
|
||||
#define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5)
|
||||
#define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4)
|
||||
#define CS42L51_ADC_CTL_SOFTB (1<<3)
|
||||
#define CS42L51_ADC_CTL_ZCROSSB (1<<2)
|
||||
#define CS42L51_ADC_CTL_SOFTA (1<<1)
|
||||
#define CS42L51_ADC_CTL_ZCROSSA (1<<0)
|
||||
|
||||
#define CS42L51_ADC_INPUT 0x07
|
||||
#define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6)
|
||||
#define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4)
|
||||
#define CS42L51_ADC_INPUT_INV_ADCB (1<<3)
|
||||
#define CS42L51_ADC_INPUT_INV_ADCA (1<<2)
|
||||
#define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1)
|
||||
#define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0)
|
||||
|
||||
#define CS42L51_DAC_OUT_CTL 0x08
|
||||
#define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5)
|
||||
#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4)
|
||||
#define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3)
|
||||
#define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2)
|
||||
#define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1)
|
||||
#define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0)
|
||||
|
||||
#define CS42L51_DAC_CTL 0x09
|
||||
#define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6)
|
||||
#define CS42L51_DAC_CTL_FREEZE (1<<5)
|
||||
#define CS42L51_DAC_CTL_DEEMPH (1<<3)
|
||||
#define CS42L51_DAC_CTL_AMUTE (1<<2)
|
||||
#define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0)
|
||||
|
||||
#define CS42L51_ALC_PGA_CTL 0x0A
|
||||
#define CS42L51_ALC_PGB_CTL 0x0B
|
||||
#define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7)
|
||||
#define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6)
|
||||
#define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0)
|
||||
|
||||
#define CS42L51_ADCA_ATT 0x0C
|
||||
#define CS42L51_ADCB_ATT 0x0D
|
||||
|
||||
#define CS42L51_ADCA_VOL 0x0E
|
||||
#define CS42L51_ADCB_VOL 0x0F
|
||||
#define CS42L51_PCMA_VOL 0x10
|
||||
#define CS42L51_PCMB_VOL 0x11
|
||||
#define CS42L51_MIX_MUTE_ADCMIX (1<<7)
|
||||
#define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0)
|
||||
|
||||
#define CS42L51_BEEP_FREQ 0x12
|
||||
#define CS42L51_BEEP_VOL 0x13
|
||||
#define CS42L51_BEEP_CONF 0x14
|
||||
|
||||
#define CS42L51_TONE_CTL 0x15
|
||||
#define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4)
|
||||
#define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0)
|
||||
|
||||
#define CS42L51_AOUTA_VOL 0x16
|
||||
#define CS42L51_AOUTB_VOL 0x17
|
||||
#define CS42L51_PCM_MIXER 0x18
|
||||
#define CS42L51_LIMIT_THRES_DIS 0x19
|
||||
#define CS42L51_LIMIT_REL 0x1A
|
||||
#define CS42L51_LIMIT_ATT 0x1B
|
||||
#define CS42L51_ALC_EN 0x1C
|
||||
#define CS42L51_ALC_REL 0x1D
|
||||
#define CS42L51_ALC_THRES 0x1E
|
||||
#define CS42L51_NOISE_CONF 0x1F
|
||||
|
||||
#define CS42L51_STATUS 0x20
|
||||
#define CS42L51_STATUS_SP_CLKERR (1<<6)
|
||||
#define CS42L51_STATUS_SPEA_OVFL (1<<5)
|
||||
#define CS42L51_STATUS_SPEB_OVFL (1<<4)
|
||||
#define CS42L51_STATUS_PCMA_OVFL (1<<3)
|
||||
#define CS42L51_STATUS_PCMB_OVFL (1<<2)
|
||||
#define CS42L51_STATUS_ADCA_OVFL (1<<1)
|
||||
#define CS42L51_STATUS_ADCB_OVFL (1<<0)
|
||||
|
||||
#define CS42L51_CHARGE_FREQ 0x21
|
||||
|
||||
#define CS42L51_FIRSTREG 0x01
|
||||
/*
|
||||
* Hack: with register 0x21, it makes 33 registers. Looks like someone in the
|
||||
* i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
|
||||
* 32 regs
|
||||
*/
|
||||
#define CS42L51_LASTREG 0x20
|
||||
#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
|
||||
|
||||
#endif
|
||||
1302
sound/soc/codecs/cs42l52.c
Normal file
1302
sound/soc/codecs/cs42l52.c
Normal file
File diff suppressed because it is too large
Load diff
274
sound/soc/codecs/cs42l52.h
Normal file
274
sound/soc/codecs/cs42l52.h
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* cs42l52.h -- CS42L52 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2012 CirrusLogic, Inc.
|
||||
*
|
||||
* Author: Georgi Vlaev <joe@nucleusys.com>
|
||||
* Author: Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS42L52_H__
|
||||
#define __CS42L52_H__
|
||||
|
||||
#define CS42L52_NAME "CS42L52"
|
||||
#define CS42L52_DEFAULT_CLK 12000000
|
||||
#define CS42L52_MIN_CLK 11000000
|
||||
#define CS42L52_MAX_CLK 27000000
|
||||
#define CS42L52_DEFAULT_FORMAT SNDRV_PCM_FMTBIT_S16_LE
|
||||
#define CS42L52_DEFAULT_MAX_CHANS 2
|
||||
#define CS42L52_SYSCLK 1
|
||||
|
||||
#define CS42L52_CHIP_SWICTH (1 << 17)
|
||||
#define CS42L52_ALL_IN_ONE (1 << 16)
|
||||
#define CS42L52_CHIP_ONE 0x00
|
||||
#define CS42L52_CHIP_TWO 0x01
|
||||
#define CS42L52_CHIP_THR 0x02
|
||||
#define CS42L52_CHIP_MASK 0x0f
|
||||
|
||||
#define CS42L52_FIX_BITS_CTL 0x00
|
||||
#define CS42L52_CHIP 0x01
|
||||
#define CS42L52_CHIP_ID 0xE0
|
||||
#define CS42L52_CHIP_ID_MASK 0xF8
|
||||
#define CS42L52_CHIP_REV_A0 0x00
|
||||
#define CS42L52_CHIP_REV_A1 0x01
|
||||
#define CS42L52_CHIP_REV_B0 0x02
|
||||
#define CS42L52_CHIP_REV_MASK 0x07
|
||||
|
||||
#define CS42L52_PWRCTL1 0x02
|
||||
#define CS42L52_PWRCTL1_PDN_ALL 0x9F
|
||||
#define CS42L52_PWRCTL1_PDN_CHRG 0x80
|
||||
#define CS42L52_PWRCTL1_PDN_PGAB 0x10
|
||||
#define CS42L52_PWRCTL1_PDN_PGAA 0x08
|
||||
#define CS42L52_PWRCTL1_PDN_ADCB 0x04
|
||||
#define CS42L52_PWRCTL1_PDN_ADCA 0x02
|
||||
#define CS42L52_PWRCTL1_PDN_CODEC 0x01
|
||||
|
||||
#define CS42L52_PWRCTL2 0x03
|
||||
#define CS42L52_PWRCTL2_OVRDB (1 << 4)
|
||||
#define CS42L52_PWRCTL2_OVRDA (1 << 3)
|
||||
#define CS42L52_PWRCTL2_PDN_MICB (1 << 2)
|
||||
#define CS42L52_PWRCTL2_PDN_MICB_SHIFT 2
|
||||
#define CS42L52_PWRCTL2_PDN_MICA (1 << 1)
|
||||
#define CS42L52_PWRCTL2_PDN_MICA_SHIFT 1
|
||||
#define CS42L52_PWRCTL2_PDN_MICBIAS (1 << 0)
|
||||
#define CS42L52_PWRCTL2_PDN_MICBIAS_SHIFT 0
|
||||
|
||||
#define CS42L52_PWRCTL3 0x04
|
||||
#define CS42L52_PWRCTL3_HPB_PDN_SHIFT 6
|
||||
#define CS42L52_PWRCTL3_HPB_ON_LOW 0x00
|
||||
#define CS42L52_PWRCTL3_HPB_ON_HIGH 0x01
|
||||
#define CS42L52_PWRCTL3_HPB_ALWAYS_ON 0x02
|
||||
#define CS42L52_PWRCTL3_HPB_ALWAYS_OFF 0x03
|
||||
#define CS42L52_PWRCTL3_HPA_PDN_SHIFT 4
|
||||
#define CS42L52_PWRCTL3_HPA_ON_LOW 0x00
|
||||
#define CS42L52_PWRCTL3_HPA_ON_HIGH 0x01
|
||||
#define CS42L52_PWRCTL3_HPA_ALWAYS_ON 0x02
|
||||
#define CS42L52_PWRCTL3_HPA_ALWAYS_OFF 0x03
|
||||
#define CS42L52_PWRCTL3_SPKB_PDN_SHIFT 2
|
||||
#define CS42L52_PWRCTL3_SPKB_ON_LOW 0x00
|
||||
#define CS42L52_PWRCTL3_SPKB_ON_HIGH 0x01
|
||||
#define CS42L52_PWRCTL3_SPKB_ALWAYS_ON 0x02
|
||||
#define CS42L52_PWRCTL3_PDN_SPKB (1 << 2)
|
||||
#define CS42L52_PWRCTL3_PDN_SPKA (1 << 0)
|
||||
#define CS42L52_PWRCTL3_SPKA_PDN_SHIFT 0
|
||||
#define CS42L52_PWRCTL3_SPKA_ON_LOW 0x00
|
||||
#define CS42L52_PWRCTL3_SPKA_ON_HIGH 0x01
|
||||
#define CS42L52_PWRCTL3_SPKA_ALWAYS_ON 0x02
|
||||
|
||||
#define CS42L52_DEFAULT_OUTPUT_STATE 0x05
|
||||
#define CS42L52_PWRCTL3_CONF_MASK 0x03
|
||||
|
||||
#define CS42L52_CLK_CTL 0x05
|
||||
#define CLK_AUTODECT_ENABLE (1 << 7)
|
||||
#define CLK_SPEED_SHIFT 5
|
||||
#define CLK_DS_MODE 0x00
|
||||
#define CLK_SS_MODE 0x01
|
||||
#define CLK_HS_MODE 0x02
|
||||
#define CLK_QS_MODE 0x03
|
||||
#define CLK_32K_SR_SHIFT 4
|
||||
#define CLK_32K 0x01
|
||||
#define CLK_NO_32K 0x00
|
||||
#define CLK_27M_MCLK_SHIFT 3
|
||||
#define CLK_27M_MCLK 0x01
|
||||
#define CLK_NO_27M 0x00
|
||||
#define CLK_RATIO_SHIFT 1
|
||||
#define CLK_R_128 0x00
|
||||
#define CLK_R_125 0x01
|
||||
#define CLK_R_132 0x02
|
||||
#define CLK_R_136 0x03
|
||||
|
||||
#define CS42L52_IFACE_CTL1 0x06
|
||||
#define CS42L52_IFACE_CTL1_MASTER (1 << 7)
|
||||
#define CS42L52_IFACE_CTL1_SLAVE (0 << 7)
|
||||
#define CS42L52_IFACE_CTL1_INV_SCLK (1 << 6)
|
||||
#define CS42L52_IFACE_CTL1_ADC_FMT_I2S (1 << 5)
|
||||
#define CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J (0 << 5)
|
||||
#define CS42L52_IFACE_CTL1_DSP_MODE_EN (1 << 4)
|
||||
#define CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J (0 << 2)
|
||||
#define CS42L52_IFACE_CTL1_DAC_FMT_I2S (1 << 2)
|
||||
#define CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J (2 << 2)
|
||||
#define CS42L52_IFACE_CTL1_WL_32BIT (0x00)
|
||||
#define CS42L52_IFACE_CTL1_WL_24BIT (0x01)
|
||||
#define CS42L52_IFACE_CTL1_WL_20BIT (0x02)
|
||||
#define CS42L52_IFACE_CTL1_WL_16BIT (0x03)
|
||||
#define CS42L52_IFACE_CTL1_WL_MASK 0xFFFF
|
||||
|
||||
#define CS42L52_IFACE_CTL2 0x07
|
||||
#define CS42L52_IFACE_CTL2_SC_MC_EQ (1 << 6)
|
||||
#define CS42L52_IFACE_CTL2_LOOPBACK (1 << 5)
|
||||
#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_EN (0 << 4)
|
||||
#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_HIZ (1 << 4)
|
||||
#define CS42L52_IFACE_CTL2_HP_SW_INV (1 << 3)
|
||||
#define CS42L52_IFACE_CTL2_BIAS_LVL 0x07
|
||||
|
||||
#define CS42L52_ADC_PGA_A 0x08
|
||||
#define CS42L52_ADC_PGA_B 0x09
|
||||
#define CS42L52_ADC_SEL_SHIFT 5
|
||||
#define CS42L52_ADC_SEL_AIN1 0x00
|
||||
#define CS42L52_ADC_SEL_AIN2 0x01
|
||||
#define CS42L52_ADC_SEL_AIN3 0x02
|
||||
#define CS42L52_ADC_SEL_AIN4 0x03
|
||||
#define CS42L52_ADC_SEL_PGA 0x04
|
||||
|
||||
#define CS42L52_ANALOG_HPF_CTL 0x0A
|
||||
#define CS42L52_HPF_CTL_ANLGSFTB (1 << 3)
|
||||
#define CS42L52_HPF_CTL_ANLGSFTA (1 << 0)
|
||||
|
||||
#define CS42L52_ADC_HPF_FREQ 0x0B
|
||||
#define CS42L52_ADC_MISC_CTL 0x0C
|
||||
#define CS42L52_ADC_MISC_CTL_SOURCE_DSP (1 << 6)
|
||||
|
||||
#define CS42L52_PB_CTL1 0x0D
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_SHIFT 5
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_03959 0x00
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_04571 0x01
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_05111 0x02
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_06047 0x03
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_07099 0x04
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_08399 0x05
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_10000 0x06
|
||||
#define CS42L52_PB_CTL1_HP_GAIN_11430 0x07
|
||||
#define CS42L52_PB_CTL1_INV_PCMB (1 << 3)
|
||||
#define CS42L52_PB_CTL1_INV_PCMA (1 << 2)
|
||||
#define CS42L52_PB_CTL1_MSTB_MUTE (1 << 1)
|
||||
#define CS42L52_PB_CTL1_MSTA_MUTE (1 << 0)
|
||||
#define CS42L52_PB_CTL1_MUTE_MASK 0x03
|
||||
#define CS42L52_PB_CTL1_MUTE 3
|
||||
#define CS42L52_PB_CTL1_UNMUTE 0
|
||||
|
||||
#define CS42L52_MISC_CTL 0x0E
|
||||
#define CS42L52_MISC_CTL_DEEMPH (1 << 2)
|
||||
#define CS42L52_MISC_CTL_DIGSFT (1 << 1)
|
||||
#define CS42L52_MISC_CTL_DIGZC (1 << 0)
|
||||
|
||||
#define CS42L52_PB_CTL2 0x0F
|
||||
#define CS42L52_PB_CTL2_HPB_MUTE (1 << 7)
|
||||
#define CS42L52_PB_CTL2_HPA_MUTE (1 << 6)
|
||||
#define CS42L52_PB_CTL2_SPKB_MUTE (1 << 5)
|
||||
#define CS42L52_PB_CTL2_SPKA_MUTE (1 << 4)
|
||||
#define CS42L52_PB_CTL2_SPK_SWAP (1 << 2)
|
||||
#define CS42L52_PB_CTL2_SPK_MONO (1 << 1)
|
||||
#define CS42L52_PB_CTL2_SPK_MUTE50 (1 << 0)
|
||||
|
||||
#define CS42L52_MICA_CTL 0x10
|
||||
#define CS42L52_MICB_CTL 0x11
|
||||
#define CS42L52_MIC_CTL_MIC_SEL_MASK 0xBF
|
||||
#define CS42L52_MIC_CTL_MIC_SEL_SHIFT 6
|
||||
#define CS42L52_MIC_CTL_TYPE_MASK 0x20
|
||||
#define CS42L52_MIC_CTL_TYPE_SHIFT 5
|
||||
|
||||
|
||||
#define CS42L52_PGAA_CTL 0x12
|
||||
#define CS42L52_PGAB_CTL 0x13
|
||||
#define CS42L52_PGAX_CTL_VOL_12DB 24
|
||||
#define CS42L52_PGAX_CTL_VOL_6DB 12 /*step size 0.5db*/
|
||||
|
||||
#define CS42L52_PASSTHRUA_VOL 0x14
|
||||
#define CS42L52_PASSTHRUB_VOL 0x15
|
||||
|
||||
#define CS42L52_ADCA_VOL 0x16
|
||||
#define CS42L52_ADCB_VOL 0x17
|
||||
#define CS42L52_ADCX_VOL_24DB 24 /*step size 1db*/
|
||||
#define CS42L52_ADCX_VOL_12DB 12
|
||||
#define CS42L52_ADCX_VOL_6DB 6
|
||||
|
||||
#define CS42L52_ADCA_MIXER_VOL 0x18
|
||||
#define CS42L52_ADCB_MIXER_VOL 0x19
|
||||
#define CS42L52_ADC_MIXER_VOL_12DB 0x18
|
||||
|
||||
#define CS42L52_PCMA_MIXER_VOL 0x1A
|
||||
#define CS42L52_PCMB_MIXER_VOL 0x1B
|
||||
|
||||
#define CS42L52_BEEP_FREQ 0x1C
|
||||
#define CS42L52_BEEP_VOL 0x1D
|
||||
#define CS42L52_BEEP_TONE_CTL 0x1E
|
||||
#define CS42L52_BEEP_RATE_SHIFT 4
|
||||
#define CS42L52_BEEP_RATE_MASK 0x0F
|
||||
|
||||
#define CS42L52_TONE_CTL 0x1F
|
||||
#define CS42L52_BEEP_EN_MASK 0x3F
|
||||
|
||||
#define CS42L52_MASTERA_VOL 0x20
|
||||
#define CS42L52_MASTERB_VOL 0x21
|
||||
|
||||
#define CS42L52_HPA_VOL 0x22
|
||||
#define CS42L52_HPB_VOL 0x23
|
||||
#define CS42L52_DEFAULT_HP_VOL 0xF0
|
||||
|
||||
#define CS42L52_SPKA_VOL 0x24
|
||||
#define CS42L52_SPKB_VOL 0x25
|
||||
#define CS42L52_DEFAULT_SPK_VOL 0xF0
|
||||
|
||||
#define CS42L52_ADC_PCM_MIXER 0x26
|
||||
|
||||
#define CS42L52_LIMITER_CTL1 0x27
|
||||
#define CS42L52_LIMITER_CTL2 0x28
|
||||
#define CS42L52_LIMITER_AT_RATE 0x29
|
||||
|
||||
#define CS42L52_ALC_CTL 0x2A
|
||||
#define CS42L52_ALC_CTL_ALCB_ENABLE_SHIFT 7
|
||||
#define CS42L52_ALC_CTL_ALCA_ENABLE_SHIFT 6
|
||||
#define CS42L52_ALC_CTL_FASTEST_ATTACK 0
|
||||
|
||||
#define CS42L52_ALC_RATE 0x2B
|
||||
#define CS42L52_ALC_SLOWEST_RELEASE 0x3F
|
||||
|
||||
#define CS42L52_ALC_THRESHOLD 0x2C
|
||||
#define CS42L52_ALC_MAX_RATE_SHIFT 5
|
||||
#define CS42L52_ALC_MIN_RATE_SHIFT 2
|
||||
#define CS42L52_ALC_RATE_0DB 0
|
||||
#define CS42L52_ALC_RATE_3DB 1
|
||||
#define CS42L52_ALC_RATE_6DB 2
|
||||
|
||||
#define CS42L52_NOISE_GATE_CTL 0x2D
|
||||
#define CS42L52_NG_ENABLE_SHIFT 6
|
||||
#define CS42L52_NG_THRESHOLD_SHIFT 2
|
||||
#define CS42L52_NG_MIN_70DB 2
|
||||
#define CS42L52_NG_DELAY_SHIFT 0
|
||||
#define CS42L52_NG_DELAY_100MS 1
|
||||
|
||||
#define CS42L52_CLK_STATUS 0x2E
|
||||
#define CS42L52_BATT_COMPEN 0x2F
|
||||
|
||||
#define CS42L52_BATT_LEVEL 0x30
|
||||
#define CS42L52_SPK_STATUS 0x31
|
||||
#define CS42L52_SPK_STATUS_PIN_SHIFT 3
|
||||
#define CS42L52_SPK_STATUS_PIN_HIGH 1
|
||||
|
||||
#define CS42L52_TEM_CTL 0x32
|
||||
#define CS42L52_TEM_CTL_SET 0x80
|
||||
#define CS42L52_THE_FOLDBACK 0x33
|
||||
#define CS42L52_CHARGE_PUMP 0x34
|
||||
#define CS42L52_CHARGE_PUMP_MASK 0xF0
|
||||
#define CS42L52_CHARGE_PUMP_SHIFT 4
|
||||
#define CS42L52_FIX_BITS1 0x3E
|
||||
#define CS42L52_FIX_BITS2 0x47
|
||||
|
||||
#define CS42L52_MAX_REGISTER 0x47
|
||||
|
||||
#endif
|
||||
1424
sound/soc/codecs/cs42l56.c
Normal file
1424
sound/soc/codecs/cs42l56.c
Normal file
File diff suppressed because it is too large
Load diff
177
sound/soc/codecs/cs42l56.h
Normal file
177
sound/soc/codecs/cs42l56.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* cs42l52.h -- CS42L56 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2014 CirrusLogic, Inc.
|
||||
*
|
||||
* Author: Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS42L56_H__
|
||||
#define __CS42L56_H__
|
||||
|
||||
#define CS42L56_CHIP_ID_1 0x01
|
||||
#define CS42L56_CHIP_ID_2 0x02
|
||||
#define CS42L56_PWRCTL_1 0x03
|
||||
#define CS42L56_PWRCTL_2 0x04
|
||||
#define CS42L56_CLKCTL_1 0x05
|
||||
#define CS42L56_CLKCTL_2 0x06
|
||||
#define CS42L56_SERIAL_FMT 0x07
|
||||
#define CS42L56_CLASSH_CTL 0x08
|
||||
#define CS42L56_MISC_CTL 0x09
|
||||
#define CS42L56_INT_STATUS 0x0a
|
||||
#define CS42L56_PLAYBACK_CTL 0x0b
|
||||
#define CS42L56_DSP_MUTE_CTL 0x0c
|
||||
#define CS42L56_ADCA_MIX_VOLUME 0x0d
|
||||
#define CS42L56_ADCB_MIX_VOLUME 0x0e
|
||||
#define CS42L56_PCMA_MIX_VOLUME 0x0f
|
||||
#define CS42L56_PCMB_MIX_VOLUME 0x10
|
||||
#define CS42L56_ANAINPUT_ADV_VOLUME 0x11
|
||||
#define CS42L56_DIGINPUT_ADV_VOLUME 0x12
|
||||
#define CS42L56_MASTER_A_VOLUME 0x13
|
||||
#define CS42L56_MASTER_B_VOLUME 0x14
|
||||
#define CS42L56_BEEP_FREQ_ONTIME 0x15
|
||||
#define CS42L56_BEEP_FREQ_OFFTIME 0x16
|
||||
#define CS42L56_BEEP_TONE_CFG 0x17
|
||||
#define CS42L56_TONE_CTL 0x18
|
||||
#define CS42L56_CHAN_MIX_SWAP 0x19
|
||||
#define CS42L56_AIN_REFCFG_ADC_MUX 0x1a
|
||||
#define CS42L56_HPF_CTL 0x1b
|
||||
#define CS42L56_MISC_ADC_CTL 0x1c
|
||||
#define CS42L56_GAIN_BIAS_CTL 0x1d
|
||||
#define CS42L56_PGAA_MUX_VOLUME 0x1e
|
||||
#define CS42L56_PGAB_MUX_VOLUME 0x1f
|
||||
#define CS42L56_ADCA_ATTENUATOR 0x20
|
||||
#define CS42L56_ADCB_ATTENUATOR 0x21
|
||||
#define CS42L56_ALC_EN_ATTACK_RATE 0x22
|
||||
#define CS42L56_ALC_RELEASE_RATE 0x23
|
||||
#define CS42L56_ALC_THRESHOLD 0x24
|
||||
#define CS42L56_NOISE_GATE_CTL 0x25
|
||||
#define CS42L56_ALC_LIM_SFT_ZC 0x26
|
||||
#define CS42L56_AMUTE_HPLO_MUX 0x27
|
||||
#define CS42L56_HPA_VOLUME 0x28
|
||||
#define CS42L56_HPB_VOLUME 0x29
|
||||
#define CS42L56_LOA_VOLUME 0x2a
|
||||
#define CS42L56_LOB_VOLUME 0x2b
|
||||
#define CS42L56_LIM_THRESHOLD_CTL 0x2c
|
||||
#define CS42L56_LIM_CTL_RELEASE_RATE 0x2d
|
||||
#define CS42L56_LIM_ATTACK_RATE 0x2e
|
||||
|
||||
/* Device ID and Rev ID Masks */
|
||||
#define CS42L56_DEVID 0x56
|
||||
#define CS42L56_CHIP_ID_MASK 0xff
|
||||
#define CS42L56_AREV_MASK 0x1c
|
||||
#define CS42L56_MTLREV_MASK 0x03
|
||||
|
||||
/* Power bit masks */
|
||||
#define CS42L56_PDN_ALL_MASK 0x01
|
||||
#define CS42L56_PDN_ADCA_MASK 0x02
|
||||
#define CS42L56_PDN_ADCB_MASK 0x04
|
||||
#define CS42L56_PDN_CHRG_MASK 0x08
|
||||
#define CS42L56_PDN_BIAS_MASK 0x10
|
||||
#define CS42L56_PDN_VBUF_MASK 0x20
|
||||
#define CS42L56_PDN_LOA_MASK 0x03
|
||||
#define CS42L56_PDN_LOB_MASK 0x0c
|
||||
#define CS42L56_PDN_HPA_MASK 0x30
|
||||
#define CS42L56_PDN_HPB_MASK 0xc0
|
||||
|
||||
/* serial port and clk masks */
|
||||
#define CS42L56_MASTER_MODE 0x40
|
||||
#define CS42L56_SLAVE_MODE 0
|
||||
#define CS42L56_MS_MODE_MASK 0x40
|
||||
#define CS42L56_SCLK_INV 0x20
|
||||
#define CS42L56_SCLK_INV_MASK 0x20
|
||||
#define CS42L56_SCLK_MCLK_MASK 0x18
|
||||
#define CS42L56_MCLK_PREDIV 0x04
|
||||
#define CS42L56_MCLK_PREDIV_MASK 0x04
|
||||
#define CS42L56_MCLK_DIV2 0x02
|
||||
#define CS42L56_MCLK_DIV2_MASK 0x02
|
||||
#define CS42L56_MCLK_DIS_MASK 0x01
|
||||
#define CS42L56_CLK_AUTO_MASK 0x20
|
||||
#define CS42L56_CLK_RATIO_MASK 0x1f
|
||||
#define CS42L56_DIG_FMT_I2S 0
|
||||
#define CS42L56_DIG_FMT_LEFT_J 0x08
|
||||
#define CS42L56_DIG_FMT_MASK 0x08
|
||||
|
||||
/* Class H and misc ctl masks */
|
||||
#define CS42L56_ADAPT_PWR_MASK 0xc0
|
||||
#define CS42L56_CHRG_FREQ_MASK 0x0f
|
||||
#define CS42L56_DIG_MUX_MASK 0x80
|
||||
#define CS42L56_ANLGSFT_MASK 0x10
|
||||
#define CS42L56_ANLGZC_MASK 0x08
|
||||
#define CS42L56_DIGSFT_MASK 0x04
|
||||
#define CS42L56_FREEZE_MASK 0x01
|
||||
#define CS42L56_MIC_BIAS_MASK 0x03
|
||||
#define CS42L56_HPFA_FREQ_MASK 0x03
|
||||
#define CS42L56_HPFB_FREQ_MASK 0xc0
|
||||
#define CS42L56_AIN1A_REF_MASK 0x10
|
||||
#define CS42L56_AIN2A_REF_MASK 0x40
|
||||
#define CS42L56_AIN1B_REF_MASK 0x20
|
||||
#define CS42L56_AIN2B_REF_MASK 0x80
|
||||
|
||||
/* Playback Capture ctl masks */
|
||||
#define CS42L56_PDN_DSP_MASK 0x80
|
||||
#define CS42L56_DEEMPH_MASK 0x40
|
||||
#define CS42L56_PLYBCK_GANG_MASK 0x10
|
||||
#define CS42L56_PCM_INV_MASK 0x0c
|
||||
#define CS42L56_MUTE_ALL 0xff
|
||||
#define CS42L56_UNMUTE 0
|
||||
#define CS42L56_ADCAMIX_MUTE_MASK 0x40
|
||||
#define CS42L56_ADCBMIX_MUTE_MASK 0x80
|
||||
#define CS42L56_PCMAMIX_MUTE_MASK 0x10
|
||||
#define CS42L56_PCMBMIX_MUTE_MASK 0x20
|
||||
#define CS42L56_MSTB_MUTE_MASK 0x02
|
||||
#define CS42L56_MSTA_MUTE_MASK 0x01
|
||||
#define CS42L56_ADCA_MUTE_MASK 0x01
|
||||
#define CS42L56_ADCB_MUTE_MASK 0x02
|
||||
#define CS42L56_HP_MUTE_MASK 0x80
|
||||
#define CS42L56_LO_MUTE_MASK 0x80
|
||||
|
||||
/* Beep masks */
|
||||
#define CS42L56_BEEP_FREQ_MASK 0xf0
|
||||
#define CS42L56_BEEP_ONTIME_MASK 0x0f
|
||||
#define CS42L56_BEEP_OFFTIME_MASK 0xe0
|
||||
#define CS42L56_BEEP_CFG_MASK 0xc0
|
||||
#define CS42L56_BEEP_TREBCF_MASK 0x18
|
||||
#define CS42L56_BEEP_BASSCF_MASK 0x06
|
||||
#define CS42L56_BEEP_TCEN_MASK 0x01
|
||||
#define CS42L56_BEEP_RATE_SHIFT 4
|
||||
#define CS42L56_BEEP_EN_MASK 0x3f
|
||||
|
||||
|
||||
/* Supported MCLKS */
|
||||
#define CS42L56_MCLK_5P6448MHZ 5644800
|
||||
#define CS42L56_MCLK_6MHZ 6000000
|
||||
#define CS42L56_MCLK_6P144MHZ 6144000
|
||||
#define CS42L56_MCLK_11P2896MHZ 11289600
|
||||
#define CS42L56_MCLK_12MHZ 12000000
|
||||
#define CS42L56_MCLK_12P288MHZ 12288000
|
||||
#define CS42L56_MCLK_22P5792MHZ 22579200
|
||||
#define CS42L56_MCLK_24MHZ 24000000
|
||||
#define CS42L56_MCLK_24P576MHZ 24576000
|
||||
|
||||
/* Clock ratios */
|
||||
#define CS42L56_MCLK_LRCLK_128 0x08
|
||||
#define CS42L56_MCLK_LRCLK_125 0x09
|
||||
#define CS42L56_MCLK_LRCLK_136 0x0b
|
||||
#define CS42L56_MCLK_LRCLK_192 0x0c
|
||||
#define CS42L56_MCLK_LRCLK_187P5 0x0d
|
||||
#define CS42L56_MCLK_LRCLK_256 0x10
|
||||
#define CS42L56_MCLK_LRCLK_250 0x11
|
||||
#define CS42L56_MCLK_LRCLK_272 0x13
|
||||
#define CS42L56_MCLK_LRCLK_384 0x14
|
||||
#define CS42L56_MCLK_LRCLK_375 0x15
|
||||
#define CS42L56_MCLK_LRCLK_512 0x18
|
||||
#define CS42L56_MCLK_LRCLK_500 0x19
|
||||
#define CS42L56_MCLK_LRCLK_544 0x1b
|
||||
#define CS42L56_MCLK_LRCLK_750 0x1c
|
||||
#define CS42L56_MCLK_LRCLK_768 0x1d
|
||||
|
||||
|
||||
#define CS42L56_MAX_REGISTER 0x34
|
||||
|
||||
#endif
|
||||
1509
sound/soc/codecs/cs42l73.c
Normal file
1509
sound/soc/codecs/cs42l73.c
Normal file
File diff suppressed because it is too large
Load diff
226
sound/soc/codecs/cs42l73.h
Normal file
226
sound/soc/codecs/cs42l73.h
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* ALSA SoC CS42L73 codec driver
|
||||
*
|
||||
* Copyright 2011 Cirrus Logic, Inc.
|
||||
*
|
||||
* Author: Georgi Vlaev <joe@nucleusys.com>
|
||||
* Brian Austin <brian.austin@cirrus.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CS42L73_H__
|
||||
#define __CS42L73_H__
|
||||
|
||||
/* I2C Registers */
|
||||
/* I2C Address: 1001010[R/W] - 10010100 = 0x94(Write); 10010101 = 0x95(Read) */
|
||||
#define CS42L73_CHIP_ID 0x4a
|
||||
#define CS42L73_DEVID_AB 0x01 /* Device ID A & B [RO]. */
|
||||
#define CS42L73_DEVID_CD 0x02 /* Device ID C & D [RO]. */
|
||||
#define CS42L73_DEVID_E 0x03 /* Device ID E [RO]. */
|
||||
#define CS42L73_REVID 0x05 /* Revision ID [RO]. */
|
||||
#define CS42L73_PWRCTL1 0x06 /* Power Control 1. */
|
||||
#define CS42L73_PWRCTL2 0x07 /* Power Control 2. */
|
||||
#define CS42L73_PWRCTL3 0x08 /* Power Control 3. */
|
||||
#define CS42L73_CPFCHC 0x09 /* Charge Pump Freq. Class H Ctl. */
|
||||
#define CS42L73_OLMBMSDC 0x0A /* Output Load, MIC Bias, MIC2 SDT */
|
||||
#define CS42L73_DMMCC 0x0B /* Digital MIC & Master Clock Ctl. */
|
||||
#define CS42L73_XSPC 0x0C /* Auxiliary Serial Port (XSP) Ctl. */
|
||||
#define CS42L73_XSPMMCC 0x0D /* XSP Master Mode Clocking Control. */
|
||||
#define CS42L73_ASPC 0x0E /* Audio Serial Port (ASP) Control. */
|
||||
#define CS42L73_ASPMMCC 0x0F /* ASP Master Mode Clocking Control. */
|
||||
#define CS42L73_VSPC 0x10 /* Voice Serial Port (VSP) Control. */
|
||||
#define CS42L73_VSPMMCC 0x11 /* VSP Master Mode Clocking Control. */
|
||||
#define CS42L73_VXSPFS 0x12 /* VSP & XSP Sample Rate. */
|
||||
#define CS42L73_MIOPC 0x13 /* Misc. Input & Output Path Control. */
|
||||
#define CS42L73_ADCIPC 0x14 /* ADC/IP Control. */
|
||||
#define CS42L73_MICAPREPGAAVOL 0x15 /* MIC 1 [A] PreAmp, PGAA Vol. */
|
||||
#define CS42L73_MICBPREPGABVOL 0x16 /* MIC 2 [B] PreAmp, PGAB Vol. */
|
||||
#define CS42L73_IPADVOL 0x17 /* Input Pat7h A Digital Volume. */
|
||||
#define CS42L73_IPBDVOL 0x18 /* Input Path B Digital Volume. */
|
||||
#define CS42L73_PBDC 0x19 /* Playback Digital Control. */
|
||||
#define CS42L73_HLADVOL 0x1A /* HP/Line A Out Digital Vol. */
|
||||
#define CS42L73_HLBDVOL 0x1B /* HP/Line B Out Digital Vol. */
|
||||
#define CS42L73_SPKDVOL 0x1C /* Spkphone Out [A] Digital Vol. */
|
||||
#define CS42L73_ESLDVOL 0x1D /* Ear/Spkphone LO [B] Digital */
|
||||
#define CS42L73_HPAAVOL 0x1E /* HP A Analog Volume. */
|
||||
#define CS42L73_HPBAVOL 0x1F /* HP B Analog Volume. */
|
||||
#define CS42L73_LOAAVOL 0x20 /* Line Out A Analog Volume. */
|
||||
#define CS42L73_LOBAVOL 0x21 /* Line Out B Analog Volume. */
|
||||
#define CS42L73_STRINV 0x22 /* Stereo Input Path Adv. Vol. */
|
||||
#define CS42L73_XSPINV 0x23 /* Auxiliary Port Input Advisory Vol. */
|
||||
#define CS42L73_ASPINV 0x24 /* Audio Port Input Advisory Vol. */
|
||||
#define CS42L73_VSPINV 0x25 /* Voice Port Input Advisory Vol. */
|
||||
#define CS42L73_LIMARATEHL 0x26 /* Lmtr Attack Rate HP/Line. */
|
||||
#define CS42L73_LIMRRATEHL 0x27 /* Lmtr Ctl, Rel.Rate HP/Line. */
|
||||
#define CS42L73_LMAXHL 0x28 /* Lmtr Thresholds HP/Line. */
|
||||
#define CS42L73_LIMARATESPK 0x29 /* Lmtr Attack Rate Spkphone [A]. */
|
||||
#define CS42L73_LIMRRATESPK 0x2A /* Lmtr Ctl,Release Rate Spk. [A]. */
|
||||
#define CS42L73_LMAXSPK 0x2B /* Lmtr Thresholds Spkphone [A]. */
|
||||
#define CS42L73_LIMARATEESL 0x2C /* Lmtr Attack Rate */
|
||||
#define CS42L73_LIMRRATEESL 0x2D /* Lmtr Ctl,Release Rate */
|
||||
#define CS42L73_LMAXESL 0x2E /* Lmtr Thresholds */
|
||||
#define CS42L73_ALCARATE 0x2F /* ALC Enable, Attack Rate AB. */
|
||||
#define CS42L73_ALCRRATE 0x30 /* ALC Release Rate AB. */
|
||||
#define CS42L73_ALCMINMAX 0x31 /* ALC Thresholds AB. */
|
||||
#define CS42L73_NGCAB 0x32 /* Noise Gate Ctl AB. */
|
||||
#define CS42L73_ALCNGMC 0x33 /* ALC & Noise Gate Misc Ctl. */
|
||||
#define CS42L73_MIXERCTL 0x34 /* Mixer Control. */
|
||||
#define CS42L73_HLAIPAA 0x35 /* HP/LO Left Mixer: L. */
|
||||
#define CS42L73_HLBIPBA 0x36 /* HP/LO Right Mixer: R. */
|
||||
#define CS42L73_HLAXSPAA 0x37 /* HP/LO Left Mixer: XSP L */
|
||||
#define CS42L73_HLBXSPBA 0x38 /* HP/LO Right Mixer: XSP R */
|
||||
#define CS42L73_HLAASPAA 0x39 /* HP/LO Left Mixer: ASP L */
|
||||
#define CS42L73_HLBASPBA 0x3A /* HP/LO Right Mixer: ASP R */
|
||||
#define CS42L73_HLAVSPMA 0x3B /* HP/LO Left Mixer: VSP. */
|
||||
#define CS42L73_HLBVSPMA 0x3C /* HP/LO Right Mixer: VSP */
|
||||
#define CS42L73_XSPAIPAA 0x3D /* XSP Left Mixer: Left */
|
||||
#define CS42L73_XSPBIPBA 0x3E /* XSP Rt. Mixer: Right */
|
||||
#define CS42L73_XSPAXSPAA 0x3F /* XSP Left Mixer: XSP L */
|
||||
#define CS42L73_XSPBXSPBA 0x40 /* XSP Rt. Mixer: XSP R */
|
||||
#define CS42L73_XSPAASPAA 0x41 /* XSP Left Mixer: ASP L */
|
||||
#define CS42L73_XSPAASPBA 0x42 /* XSP Rt. Mixer: ASP R */
|
||||
#define CS42L73_XSPAVSPMA 0x43 /* XSP Left Mixer: VSP */
|
||||
#define CS42L73_XSPBVSPMA 0x44 /* XSP Rt. Mixer: VSP */
|
||||
#define CS42L73_ASPAIPAA 0x45 /* ASP Left Mixer: Left */
|
||||
#define CS42L73_ASPBIPBA 0x46 /* ASP Rt. Mixer: Right */
|
||||
#define CS42L73_ASPAXSPAA 0x47 /* ASP Left Mixer: XSP L */
|
||||
#define CS42L73_ASPBXSPBA 0x48 /* ASP Rt. Mixer: XSP R */
|
||||
#define CS42L73_ASPAASPAA 0x49 /* ASP Left Mixer: ASP L */
|
||||
#define CS42L73_ASPBASPBA 0x4A /* ASP Rt. Mixer: ASP R */
|
||||
#define CS42L73_ASPAVSPMA 0x4B /* ASP Left Mixer: VSP */
|
||||
#define CS42L73_ASPBVSPMA 0x4C /* ASP Rt. Mixer: VSP */
|
||||
#define CS42L73_VSPAIPAA 0x4D /* VSP Left Mixer: Left */
|
||||
#define CS42L73_VSPBIPBA 0x4E /* VSP Rt. Mixer: Right */
|
||||
#define CS42L73_VSPAXSPAA 0x4F /* VSP Left Mixer: XSP L */
|
||||
#define CS42L73_VSPBXSPBA 0x50 /* VSP Rt. Mixer: XSP R */
|
||||
#define CS42L73_VSPAASPAA 0x51 /* VSP Left Mixer: ASP Left */
|
||||
#define CS42L73_VSPBASPBA 0x52 /* VSP Rt. Mixer: ASP Right */
|
||||
#define CS42L73_VSPAVSPMA 0x53 /* VSP Left Mixer: VSP */
|
||||
#define CS42L73_VSPBVSPMA 0x54 /* VSP Rt. Mixer: VSP */
|
||||
#define CS42L73_MMIXCTL 0x55 /* Mono Mixer Controls. */
|
||||
#define CS42L73_SPKMIPMA 0x56 /* SPK Mono Mixer: In. Path */
|
||||
#define CS42L73_SPKMXSPA 0x57 /* SPK Mono Mixer: XSP Mono/L/R Att. */
|
||||
#define CS42L73_SPKMASPA 0x58 /* SPK Mono Mixer: ASP Mono/L/R Att. */
|
||||
#define CS42L73_SPKMVSPMA 0x59 /* SPK Mono Mixer: VSP Mono Atten. */
|
||||
#define CS42L73_ESLMIPMA 0x5A /* Ear/SpLO Mono Mixer: */
|
||||
#define CS42L73_ESLMXSPA 0x5B /* Ear/SpLO Mono Mixer: XSP */
|
||||
#define CS42L73_ESLMASPA 0x5C /* Ear/SpLO Mono Mixer: ASP */
|
||||
#define CS42L73_ESLMVSPMA 0x5D /* Ear/SpLO Mono Mixer: VSP */
|
||||
#define CS42L73_IM1 0x5E /* Interrupt Mask 1. */
|
||||
#define CS42L73_IM2 0x5F /* Interrupt Mask 2. */
|
||||
#define CS42L73_IS1 0x60 /* Interrupt Status 1 [RO]. */
|
||||
#define CS42L73_IS2 0x61 /* Interrupt Status 2 [RO]. */
|
||||
#define CS42L73_MAX_REGISTER 0x61 /* Total Registers */
|
||||
/* Bitfield Definitions */
|
||||
|
||||
/* CS42L73_PWRCTL1 */
|
||||
#define CS42L73_PDN_ADCB (1 << 7)
|
||||
#define CS42L73_PDN_DMICB (1 << 6)
|
||||
#define CS42L73_PDN_ADCA (1 << 5)
|
||||
#define CS42L73_PDN_DMICA (1 << 4)
|
||||
#define CS42L73_PDN_LDO (1 << 2)
|
||||
#define CS42L73_DISCHG_FILT (1 << 1)
|
||||
#define CS42L73_PDN (1 << 0)
|
||||
|
||||
/* CS42L73_PWRCTL2 */
|
||||
#define CS42L73_PDN_MIC2_BIAS (1 << 7)
|
||||
#define CS42L73_PDN_MIC1_BIAS (1 << 6)
|
||||
#define CS42L73_PDN_VSP (1 << 4)
|
||||
#define CS42L73_PDN_ASP_SDOUT (1 << 3)
|
||||
#define CS42L73_PDN_ASP_SDIN (1 << 2)
|
||||
#define CS42L73_PDN_XSP_SDOUT (1 << 1)
|
||||
#define CS42L73_PDN_XSP_SDIN (1 << 0)
|
||||
|
||||
/* CS42L73_PWRCTL3 */
|
||||
#define CS42L73_PDN_THMS (1 << 5)
|
||||
#define CS42L73_PDN_SPKLO (1 << 4)
|
||||
#define CS42L73_PDN_EAR (1 << 3)
|
||||
#define CS42L73_PDN_SPK (1 << 2)
|
||||
#define CS42L73_PDN_LO (1 << 1)
|
||||
#define CS42L73_PDN_HP (1 << 0)
|
||||
|
||||
/* Thermal Overload Detect. Requires interrupt ... */
|
||||
#define CS42L73_THMOVLD_150C 0
|
||||
#define CS42L73_THMOVLD_132C 1
|
||||
#define CS42L73_THMOVLD_115C 2
|
||||
#define CS42L73_THMOVLD_098C 3
|
||||
|
||||
#define CS42L73_CHARGEPUMP_MASK (0xF0)
|
||||
|
||||
/* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */
|
||||
#define CS42L73_SP_3ST (1 << 7)
|
||||
#define CS42L73_SPDIF_I2S (0 << 6)
|
||||
#define CS42L73_SPDIF_PCM (1 << 6)
|
||||
#define CS42L73_PCM_MODE0 (0 << 4)
|
||||
#define CS42L73_PCM_MODE1 (1 << 4)
|
||||
#define CS42L73_PCM_MODE2 (2 << 4)
|
||||
#define CS42L73_PCM_MODE_MASK (3 << 4)
|
||||
#define CS42L73_PCM_BIT_ORDER (1 << 3)
|
||||
#define CS42L73_MCK_SCLK_64FS (0 << 0)
|
||||
#define CS42L73_MCK_SCLK_MCLK (2 << 0)
|
||||
#define CS42L73_MCK_SCLK_PREMCLK (3 << 0)
|
||||
|
||||
/* CS42L73_xSPMMCC */
|
||||
#define CS42L73_MS_MASTER (1 << 7)
|
||||
|
||||
|
||||
/* CS42L73_DMMCC */
|
||||
#define CS42L73_MCLKDIS (1 << 0)
|
||||
#define CS42L73_MCLKSEL_MCLK2 (1 << 4)
|
||||
#define CS42L73_MCLKSEL_MCLK1 (0 << 4)
|
||||
|
||||
/* CS42L73 MCLK derived from MCLK1 or MCLK2 */
|
||||
#define CS42L73_CLKID_MCLK1 0
|
||||
#define CS42L73_CLKID_MCLK2 1
|
||||
|
||||
#define CS42L73_MCLKXDIV 0
|
||||
#define CS42L73_MMCCDIV 1
|
||||
|
||||
#define CS42L73_XSP 0
|
||||
#define CS42L73_ASP 1
|
||||
#define CS42L73_VSP 2
|
||||
|
||||
/* IS1, IM1 */
|
||||
#define CS42L73_MIC2_SDET (1 << 6)
|
||||
#define CS42L73_THMOVLD (1 << 4)
|
||||
#define CS42L73_DIGMIXOVFL (1 << 3)
|
||||
#define CS42L73_IPBOVFL (1 << 1)
|
||||
#define CS42L73_IPAOVFL (1 << 0)
|
||||
|
||||
/* Analog Softramp */
|
||||
#define CS42L73_ANLGOSFT (1 << 0)
|
||||
|
||||
/* HP A/B Analog Mute */
|
||||
#define CS42L73_HPA_MUTE (1 << 7)
|
||||
/* LO A/B Analog Mute */
|
||||
#define CS42L73_LOA_MUTE (1 << 7)
|
||||
/* Digital Mute */
|
||||
#define CS42L73_HLAD_MUTE (1 << 0)
|
||||
#define CS42L73_HLBD_MUTE (1 << 1)
|
||||
#define CS42L73_SPKD_MUTE (1 << 2)
|
||||
#define CS42L73_ESLD_MUTE (1 << 3)
|
||||
|
||||
/* Misc defines for codec */
|
||||
#define CS42L73_DEVID 0x00042A73
|
||||
#define CS42L73_MCLKX_MIN 5644800
|
||||
#define CS42L73_MCLKX_MAX 38400000
|
||||
|
||||
#define CS42L73_SPC(id) (CS42L73_XSPC + (id << 1))
|
||||
#define CS42L73_MMCC(id) (CS42L73_XSPMMCC + (id << 1))
|
||||
#define CS42L73_SPFS(id) ((id == CS42L73_ASP) ? CS42L73_ASPC : CS42L73_VXSPFS)
|
||||
|
||||
#endif /* __CS42L73_H__ */
|
||||
64
sound/soc/codecs/cs42xx8-i2c.c
Normal file
64
sound/soc/codecs/cs42xx8-i2c.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "cs42xx8.h"
|
||||
|
||||
static int cs42xx8_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
u32 ret = cs42xx8_probe(&i2c->dev,
|
||||
devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(&i2c->dev);
|
||||
pm_request_idle(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
pm_runtime_disable(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_device_id cs42xx8_i2c_id[] = {
|
||||
{"cs42448", (kernel_ulong_t)&cs42448_data},
|
||||
{"cs42888", (kernel_ulong_t)&cs42888_data},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
|
||||
|
||||
static struct i2c_driver cs42xx8_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42xx8",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cs42xx8_pm,
|
||||
},
|
||||
.probe = cs42xx8_i2c_probe,
|
||||
.remove = cs42xx8_i2c_remove,
|
||||
.id_table = cs42xx8_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs42xx8_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
603
sound/soc/codecs/cs42xx8.c
Normal file
603
sound/soc/codecs/cs42xx8.c
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
/*
|
||||
* Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "cs42xx8.h"
|
||||
|
||||
#define CS42XX8_NUM_SUPPLIES 4
|
||||
static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
|
||||
"VA",
|
||||
"VD",
|
||||
"VLS",
|
||||
"VLC",
|
||||
};
|
||||
|
||||
#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
/* codec private data */
|
||||
struct cs42xx8_priv {
|
||||
struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
|
||||
const struct cs42xx8_driver_data *drvdata;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
|
||||
bool slave_mode;
|
||||
unsigned long sysclk;
|
||||
};
|
||||
|
||||
/* -127.5dB to 0dB with step of 0.5dB */
|
||||
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
|
||||
/* -64dB to 24dB with step of 0.5dB */
|
||||
static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
|
||||
|
||||
static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
|
||||
static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
|
||||
"Soft Ramp", "Soft Ramp on Zero Cross" };
|
||||
|
||||
static const struct soc_enum adc1_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum adc2_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum adc3_single_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
|
||||
static const struct soc_enum dac_szc_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
|
||||
static const struct soc_enum adc_szc_enum =
|
||||
SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
|
||||
|
||||
static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
|
||||
CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
|
||||
CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
|
||||
CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
|
||||
CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
|
||||
SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
|
||||
CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
|
||||
CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
|
||||
SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
|
||||
SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
|
||||
SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
|
||||
SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
|
||||
SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
|
||||
SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
|
||||
SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
|
||||
SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
|
||||
SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
|
||||
SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
|
||||
SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
|
||||
SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
|
||||
SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
|
||||
SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
|
||||
SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
|
||||
SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
|
||||
CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
|
||||
SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
|
||||
SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
|
||||
SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
|
||||
SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
|
||||
SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUT1L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT1R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT2L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT2R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT3L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT3R"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT4L"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUT4R"),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
|
||||
SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
|
||||
|
||||
SND_SOC_DAPM_INPUT("AIN1L"),
|
||||
SND_SOC_DAPM_INPUT("AIN1R"),
|
||||
SND_SOC_DAPM_INPUT("AIN2L"),
|
||||
SND_SOC_DAPM_INPUT("AIN2R"),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
|
||||
|
||||
SND_SOC_DAPM_INPUT("AIN3L"),
|
||||
SND_SOC_DAPM_INPUT("AIN3R"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
|
||||
/* Playback */
|
||||
{ "AOUT1L", NULL, "DAC1" },
|
||||
{ "AOUT1R", NULL, "DAC1" },
|
||||
{ "DAC1", NULL, "PWR" },
|
||||
|
||||
{ "AOUT2L", NULL, "DAC2" },
|
||||
{ "AOUT2R", NULL, "DAC2" },
|
||||
{ "DAC2", NULL, "PWR" },
|
||||
|
||||
{ "AOUT3L", NULL, "DAC3" },
|
||||
{ "AOUT3R", NULL, "DAC3" },
|
||||
{ "DAC3", NULL, "PWR" },
|
||||
|
||||
{ "AOUT4L", NULL, "DAC4" },
|
||||
{ "AOUT4R", NULL, "DAC4" },
|
||||
{ "DAC4", NULL, "PWR" },
|
||||
|
||||
/* Capture */
|
||||
{ "ADC1", NULL, "AIN1L" },
|
||||
{ "ADC1", NULL, "AIN1R" },
|
||||
{ "ADC1", NULL, "PWR" },
|
||||
|
||||
{ "ADC2", NULL, "AIN2L" },
|
||||
{ "ADC2", NULL, "AIN2R" },
|
||||
{ "ADC2", NULL, "PWR" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
|
||||
/* Capture */
|
||||
{ "ADC3", NULL, "AIN3L" },
|
||||
{ "ADC3", NULL, "AIN3R" },
|
||||
{ "ADC3", NULL, "PWR" },
|
||||
};
|
||||
|
||||
struct cs42xx8_ratios {
|
||||
unsigned int ratio;
|
||||
unsigned char speed;
|
||||
unsigned char mclk;
|
||||
};
|
||||
|
||||
static const struct cs42xx8_ratios cs42xx8_ratios[] = {
|
||||
{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
|
||||
{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
|
||||
{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
|
||||
{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
|
||||
{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
|
||||
{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
|
||||
{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
|
||||
{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
|
||||
{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
|
||||
};
|
||||
|
||||
static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
cs42xx8->sysclk = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
u32 val;
|
||||
|
||||
/* Set DAI format */
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported dai format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
|
||||
CS42XX8_INTF_DAC_DIF_MASK |
|
||||
CS42XX8_INTF_ADC_DIF_MASK, val);
|
||||
|
||||
/* Set master/slave audio interface */
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
cs42xx8->slave_mode = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
cs42xx8->slave_mode = false;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported master/slave mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 ratio = cs42xx8->sysclk / params_rate(params);
|
||||
u32 i, fm, val, mask;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
|
||||
if (cs42xx8_ratios[i].ratio == ratio)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cs42xx8_ratios)) {
|
||||
dev_err(codec->dev, "unsupported sysclk ratio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mask = CS42XX8_FUNCMOD_MFREQ_MASK;
|
||||
val = cs42xx8_ratios[i].mclk;
|
||||
|
||||
fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
|
||||
CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
|
||||
CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
|
||||
CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
|
||||
.set_fmt = cs42xx8_set_dai_fmt,
|
||||
.set_sysclk = cs42xx8_set_dai_sysclk,
|
||||
.hw_params = cs42xx8_hw_params,
|
||||
.digital_mute = cs42xx8_digital_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs42xx8_dai = {
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = CS42XX8_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = CS42XX8_FORMATS,
|
||||
},
|
||||
.ops = &cs42xx8_dai_ops,
|
||||
};
|
||||
|
||||
static const struct reg_default cs42xx8_reg[] = {
|
||||
{ 0x01, 0x01 }, /* Chip I.D. and Revision Register */
|
||||
{ 0x02, 0x00 }, /* Power Control */
|
||||
{ 0x03, 0xF0 }, /* Functional Mode */
|
||||
{ 0x04, 0x46 }, /* Interface Formats */
|
||||
{ 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */
|
||||
{ 0x06, 0x10 }, /* Transition Control */
|
||||
{ 0x07, 0x00 }, /* DAC Channel Mute */
|
||||
{ 0x08, 0x00 }, /* Volume Control AOUT1 */
|
||||
{ 0x09, 0x00 }, /* Volume Control AOUT2 */
|
||||
{ 0x0a, 0x00 }, /* Volume Control AOUT3 */
|
||||
{ 0x0b, 0x00 }, /* Volume Control AOUT4 */
|
||||
{ 0x0c, 0x00 }, /* Volume Control AOUT5 */
|
||||
{ 0x0d, 0x00 }, /* Volume Control AOUT6 */
|
||||
{ 0x0e, 0x00 }, /* Volume Control AOUT7 */
|
||||
{ 0x0f, 0x00 }, /* Volume Control AOUT8 */
|
||||
{ 0x10, 0x00 }, /* DAC Channel Invert */
|
||||
{ 0x11, 0x00 }, /* Volume Control AIN1 */
|
||||
{ 0x12, 0x00 }, /* Volume Control AIN2 */
|
||||
{ 0x13, 0x00 }, /* Volume Control AIN3 */
|
||||
{ 0x14, 0x00 }, /* Volume Control AIN4 */
|
||||
{ 0x15, 0x00 }, /* Volume Control AIN5 */
|
||||
{ 0x16, 0x00 }, /* Volume Control AIN6 */
|
||||
{ 0x17, 0x00 }, /* ADC Channel Invert */
|
||||
{ 0x18, 0x00 }, /* Status Control */
|
||||
{ 0x1a, 0x00 }, /* Status Mask */
|
||||
{ 0x1b, 0x00 }, /* MUTEC Pin Control */
|
||||
};
|
||||
|
||||
static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS42XX8_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS42XX8_CHIPID:
|
||||
case CS42XX8_STATUS:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config cs42xx8_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = CS42XX8_LASTREG,
|
||||
.reg_defaults = cs42xx8_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
|
||||
.volatile_reg = cs42xx8_volatile_register,
|
||||
.writeable_reg = cs42xx8_writeable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
|
||||
|
||||
static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
switch (cs42xx8->drvdata->num_adcs) {
|
||||
case 3:
|
||||
snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
|
||||
ARRAY_SIZE(cs42xx8_adc3_snd_controls));
|
||||
snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
|
||||
ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
|
||||
ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mute all DAC channels */
|
||||
regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver cs42xx8_driver = {
|
||||
.probe = cs42xx8_codec_probe,
|
||||
.idle_bias_off = true,
|
||||
|
||||
.controls = cs42xx8_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
|
||||
.dapm_widgets = cs42xx8_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
|
||||
.dapm_routes = cs42xx8_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
|
||||
};
|
||||
|
||||
const struct cs42xx8_driver_data cs42448_data = {
|
||||
.name = "cs42448",
|
||||
.num_adcs = 3,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42448_data);
|
||||
|
||||
const struct cs42xx8_driver_data cs42888_data = {
|
||||
.name = "cs42888",
|
||||
.num_adcs = 2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42888_data);
|
||||
|
||||
static const struct of_device_id cs42xx8_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
|
||||
{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_of_match);
|
||||
|
||||
int cs42xx8_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
|
||||
struct cs42xx8_priv *cs42xx8;
|
||||
int ret, val, i;
|
||||
|
||||
cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
|
||||
if (cs42xx8 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, cs42xx8);
|
||||
|
||||
if (of_id)
|
||||
cs42xx8->drvdata = of_id->data;
|
||||
|
||||
if (!cs42xx8->drvdata) {
|
||||
dev_err(dev, "failed to find driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cs42xx8->clk = devm_clk_get(dev, "mclk");
|
||||
if (IS_ERR(cs42xx8->clk)) {
|
||||
dev_err(dev, "failed to get the clock: %ld\n",
|
||||
PTR_ERR(cs42xx8->clk));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
|
||||
cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev,
|
||||
ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make sure hardware reset done */
|
||||
msleep(5);
|
||||
|
||||
cs42xx8->regmap = regmap;
|
||||
if (IS_ERR(cs42xx8->regmap)) {
|
||||
ret = PTR_ERR(cs42xx8->regmap);
|
||||
dev_err(dev, "failed to allocate regmap: %d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
/*
|
||||
* We haven't marked the chip revision as volatile due to
|
||||
* sharing a register with the right input volume; explicitly
|
||||
* bypass the cache to read it.
|
||||
*/
|
||||
regcache_cache_bypass(cs42xx8->regmap, true);
|
||||
|
||||
/* Validate the chip ID */
|
||||
ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get device ID, ret = %d", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
/* The top four bits of the chip ID should be 0000 */
|
||||
if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
|
||||
dev_err(dev, "unmatched chip ID: %d\n",
|
||||
(val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
|
||||
ret = -EINVAL;
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
dev_info(dev, "found device, revision %X\n",
|
||||
val & CS42XX8_CHIPID_REV_ID_MASK);
|
||||
|
||||
regcache_cache_bypass(cs42xx8->regmap, false);
|
||||
|
||||
cs42xx8_dai.name = cs42xx8->drvdata->name;
|
||||
|
||||
/* Each adc supports stereo input */
|
||||
cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
|
||||
|
||||
ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register codec:%d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, true);
|
||||
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_probe);
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int cs42xx8_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(cs42xx8->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable mclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable supplies: %d\n", ret);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* Make sure hardware reset done */
|
||||
msleep(5);
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, false);
|
||||
|
||||
ret = regcache_sync(cs42xx8->regmap);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to sync regmap: %d\n", ret);
|
||||
goto err_bulk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_bulk:
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
err_clk:
|
||||
clk_disable_unprepare(cs42xx8->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42xx8_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, true);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
|
||||
cs42xx8->supplies);
|
||||
|
||||
clk_disable_unprepare(cs42xx8->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct dev_pm_ops cs42xx8_pm = {
|
||||
SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_pm);
|
||||
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
238
sound/soc/codecs/cs42xx8.h
Normal file
238
sound/soc/codecs/cs42xx8.h
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author: Nicolin Chen <Guangyu.Chen@freescale.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _CS42XX8_H
|
||||
#define _CS42XX8_H
|
||||
|
||||
struct cs42xx8_driver_data {
|
||||
char name[32];
|
||||
int num_adcs;
|
||||
};
|
||||
|
||||
extern const struct dev_pm_ops cs42xx8_pm;
|
||||
extern const struct cs42xx8_driver_data cs42448_data;
|
||||
extern const struct cs42xx8_driver_data cs42888_data;
|
||||
extern const struct regmap_config cs42xx8_regmap_config;
|
||||
int cs42xx8_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
/* CS42888 register map */
|
||||
#define CS42XX8_CHIPID 0x01 /* Chip ID */
|
||||
#define CS42XX8_PWRCTL 0x02 /* Power Control */
|
||||
#define CS42XX8_FUNCMOD 0x03 /* Functional Mode */
|
||||
#define CS42XX8_INTF 0x04 /* Interface Formats */
|
||||
#define CS42XX8_ADCCTL 0x05 /* ADC Control */
|
||||
#define CS42XX8_TXCTL 0x06 /* Transition Control */
|
||||
#define CS42XX8_DACMUTE 0x07 /* DAC Mute Control */
|
||||
#define CS42XX8_VOLAOUT1 0x08 /* Volume Control AOUT1 */
|
||||
#define CS42XX8_VOLAOUT2 0x09 /* Volume Control AOUT2 */
|
||||
#define CS42XX8_VOLAOUT3 0x0A /* Volume Control AOUT3 */
|
||||
#define CS42XX8_VOLAOUT4 0x0B /* Volume Control AOUT4 */
|
||||
#define CS42XX8_VOLAOUT5 0x0C /* Volume Control AOUT5 */
|
||||
#define CS42XX8_VOLAOUT6 0x0D /* Volume Control AOUT6 */
|
||||
#define CS42XX8_VOLAOUT7 0x0E /* Volume Control AOUT7 */
|
||||
#define CS42XX8_VOLAOUT8 0x0F /* Volume Control AOUT8 */
|
||||
#define CS42XX8_DACINV 0x10 /* DAC Channel Invert */
|
||||
#define CS42XX8_VOLAIN1 0x11 /* Volume Control AIN1 */
|
||||
#define CS42XX8_VOLAIN2 0x12 /* Volume Control AIN2 */
|
||||
#define CS42XX8_VOLAIN3 0x13 /* Volume Control AIN3 */
|
||||
#define CS42XX8_VOLAIN4 0x14 /* Volume Control AIN4 */
|
||||
#define CS42XX8_VOLAIN5 0x15 /* Volume Control AIN5 */
|
||||
#define CS42XX8_VOLAIN6 0x16 /* Volume Control AIN6 */
|
||||
#define CS42XX8_ADCINV 0x17 /* ADC Channel Invert */
|
||||
#define CS42XX8_STATUSCTL 0x18 /* Status Control */
|
||||
#define CS42XX8_STATUS 0x19 /* Status */
|
||||
#define CS42XX8_STATUSM 0x1A /* Status Mask */
|
||||
#define CS42XX8_MUTEC 0x1B /* MUTEC Pin Control */
|
||||
|
||||
#define CS42XX8_FIRSTREG CS42XX8_CHIPID
|
||||
#define CS42XX8_LASTREG CS42XX8_MUTEC
|
||||
#define CS42XX8_NUMREGS (CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
|
||||
#define CS42XX8_I2C_INCR 0x80
|
||||
|
||||
/* Chip I.D. and Revision Register (Address 01h) */
|
||||
#define CS42XX8_CHIPID_CHIP_ID_MASK 0xF0
|
||||
#define CS42XX8_CHIPID_REV_ID_MASK 0x0F
|
||||
|
||||
/* Power Control (Address 02h) */
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT 7
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3_MASK (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC3 (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT 6
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2_MASK (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC2 (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT 5
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1_MASK (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_ADC1 (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT 4
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4_MASK (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC4 (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT 3
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3_MASK (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC3 (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT 2
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2_MASK (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC2 (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT 1
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1_MASK (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_DAC1 (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN_SHIFT 0
|
||||
#define CS42XX8_PWRCTL_PDN_MASK (1 << CS42XX8_PWRCTL_PDN_SHIFT)
|
||||
#define CS42XX8_PWRCTL_PDN (1 << CS42XX8_PWRCTL_PDN_SHIFT)
|
||||
|
||||
/* Functional Mode (Address 03h) */
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_SHIFT 6
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_WIDTH 2
|
||||
#define CS42XX8_FUNCMOD_DAC_FM_MASK (((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_DAC_FM(v) ((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_SHIFT 4
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_WIDTH 2
|
||||
#define CS42XX8_FUNCMOD_ADC_FM_MASK (((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_ADC_FM(v) ((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_xC_FM_MASK(x) ((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
|
||||
#define CS42XX8_FUNCMOD_xC_FM(x, v) ((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_SHIFT 1
|
||||
#define CS42XX8_FUNCMOD_MFREQ_WIDTH 3
|
||||
#define CS42XX8_FUNCMOD_MFREQ_MASK (((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
|
||||
#define CS42XX8_FUNCMOD_MFREQ_256(s) ((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_384(s) ((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_512(s) ((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_768(s) ((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
#define CS42XX8_FUNCMOD_MFREQ_1024(s) ((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
|
||||
|
||||
#define CS42XX8_FM_SINGLE 0
|
||||
#define CS42XX8_FM_DOUBLE 1
|
||||
#define CS42XX8_FM_QUAD 2
|
||||
#define CS42XX8_FM_AUTO 3
|
||||
|
||||
/* Interface Formats (Address 04h) */
|
||||
#define CS42XX8_INTF_FREEZE_SHIFT 7
|
||||
#define CS42XX8_INTF_FREEZE_MASK (1 << CS42XX8_INTF_FREEZE_SHIFT)
|
||||
#define CS42XX8_INTF_FREEZE (1 << CS42XX8_INTF_FREEZE_SHIFT)
|
||||
#define CS42XX8_INTF_AUX_DIF_SHIFT 6
|
||||
#define CS42XX8_INTF_AUX_DIF_MASK (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_AUX_DIF (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_SHIFT 3
|
||||
#define CS42XX8_INTF_DAC_DIF_WIDTH 3
|
||||
#define CS42XX8_INTF_DAC_DIF_MASK (((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_LEFTJ (0 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_I2S (1 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (5 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_DAC_DIF_TDM (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_SHIFT 0
|
||||
#define CS42XX8_INTF_ADC_DIF_WIDTH 3
|
||||
#define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_LEFTJ (0 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_I2S (1 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (5 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
#define CS42XX8_INTF_ADC_DIF_TDM (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
|
||||
|
||||
/* ADC Control & DAC De-Emphasis (Address 05h) */
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_DAC_DEM_SHIFT 5
|
||||
#define CS42XX8_ADCCTL_DAC_DEM_MASK (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
|
||||
#define CS42XX8_ADCCTL_DAC_DEM (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT 4
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC1_SINGLE (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT 3
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC2_SINGLE (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT 2
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_ADC3_SINGLE (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT 1
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX_MASK (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN5_MUX (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT 0
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX_MASK (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
|
||||
#define CS42XX8_ADCCTL_AIN6_MUX (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
|
||||
|
||||
/* Transition Control (Address 06h) */
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT 7
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL_MASK (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SNGVOL (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SHIFT 5
|
||||
#define CS42XX8_TXCTL_DAC_SZC_WIDTH 2
|
||||
#define CS42XX8_TXCTL_DAC_SZC_MASK (((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_IC (0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_ZC (1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SR (2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_DAC_SZC_SRZC (3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_AMUTE_SHIFT 4
|
||||
#define CS42XX8_TXCTL_AMUTE_MASK (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
|
||||
#define CS42XX8_TXCTL_AMUTE (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT 3
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
|
||||
#define CS42XX8_TXCTL_MUTE_ADC_SP (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT 2
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL_MASK (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SNGVOL (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SHIFT 0
|
||||
#define CS42XX8_TXCTL_ADC_SZC_MASK (((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_IC (0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_ZC (1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SR (2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
#define CS42XX8_TXCTL_ADC_SZC_SRZC (3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
|
||||
|
||||
/* DAC Channel Mute (Address 07h) */
|
||||
#define CS42XX8_DACMUTE_AOUT(n) (0x1 << n)
|
||||
#define CS42XX8_DACMUTE_ALL 0xff
|
||||
|
||||
/* Status Control (Address 18h)*/
|
||||
#define CS42XX8_STATUSCTL_INI_SHIFT 2
|
||||
#define CS42XX8_STATUSCTL_INI_WIDTH 2
|
||||
#define CS42XX8_STATUSCTL_INI_MASK (((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH (0 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW (1 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN (2 << CS42XX8_STATUSCTL_INI_SHIFT)
|
||||
|
||||
/* Status (Address 19h)*/
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT 4
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT 3
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_SHIFT 2
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_SHIFT 1
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_SHIFT 0
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
|
||||
|
||||
/* Status Mask (Address 1Ah) */
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT 4
|
||||
#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT 3
|
||||
#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT 2
|
||||
#define CS42XX8_STATUS_ADC3_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT 1
|
||||
#define CS42XX8_STATUS_ADC2_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT 0
|
||||
#define CS42XX8_STATUS_ADC1_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
|
||||
|
||||
/* MUTEC Pin Control (Address 1Bh) */
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_SHIFT 1
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_MASK (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW (0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT 0
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
|
||||
#define CS42XX8_MUTEC_MUTEC_ACTIVE (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
|
||||
#endif /* _CS42XX8_H */
|
||||
443
sound/soc/codecs/cx20442.c
Normal file
443
sound/soc/codecs/cx20442.c
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* cx20442.c -- CX20442 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
|
||||
*
|
||||
* Initially based on sound/soc/codecs/wm8400.c
|
||||
* Copyright 2008, 2009 Wolfson Microelectronics PLC.
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/tty.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "cx20442.h"
|
||||
|
||||
|
||||
struct cx20442_priv {
|
||||
void *control_data;
|
||||
struct regulator *por;
|
||||
};
|
||||
|
||||
#define CX20442_PM 0x0
|
||||
|
||||
#define CX20442_TELIN 0
|
||||
#define CX20442_TELOUT 1
|
||||
#define CX20442_MIC 2
|
||||
#define CX20442_SPKOUT 3
|
||||
#define CX20442_AGC 4
|
||||
|
||||
static const struct snd_soc_dapm_widget cx20442_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("TELOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("SPKOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("AGCOUT"),
|
||||
|
||||
SND_SOC_DAPM_MIXER("SPKOUT Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("TELOUT Amp", CX20442_PM, CX20442_TELOUT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("SPKOUT Amp", CX20442_PM, CX20442_SPKOUT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("SPKOUT AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
|
||||
SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MICBIAS("TELIN Bias", CX20442_PM, CX20442_TELIN, 0),
|
||||
SND_SOC_DAPM_MICBIAS("MIC Bias", CX20442_PM, CX20442_MIC, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("MIC AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_INPUT("TELIN"),
|
||||
SND_SOC_DAPM_INPUT("MIC"),
|
||||
SND_SOC_DAPM_INPUT("AGCIN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cx20442_audio_map[] = {
|
||||
{"TELOUT", NULL, "TELOUT Amp"},
|
||||
|
||||
{"SPKOUT", NULL, "SPKOUT Mixer"},
|
||||
{"SPKOUT Mixer", NULL, "SPKOUT Amp"},
|
||||
|
||||
{"TELOUT Amp", NULL, "DAC"},
|
||||
{"SPKOUT Amp", NULL, "DAC"},
|
||||
|
||||
{"SPKOUT Mixer", NULL, "SPKOUT AGC"},
|
||||
{"SPKOUT AGC", NULL, "AGCIN"},
|
||||
|
||||
{"AGCOUT", NULL, "MIC AGC"},
|
||||
{"MIC AGC", NULL, "MIC"},
|
||||
|
||||
{"MIC Bias", NULL, "MIC"},
|
||||
{"Input Mixer", NULL, "MIC Bias"},
|
||||
|
||||
{"TELIN Bias", NULL, "TELIN"},
|
||||
{"Input Mixer", NULL, "TELIN Bias"},
|
||||
|
||||
{"ADC", NULL, "Input Mixer"},
|
||||
};
|
||||
|
||||
static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
return reg_cache[reg];
|
||||
}
|
||||
|
||||
enum v253_vls {
|
||||
V253_VLS_NONE = 0,
|
||||
V253_VLS_T,
|
||||
V253_VLS_L,
|
||||
V253_VLS_LT,
|
||||
V253_VLS_S,
|
||||
V253_VLS_ST,
|
||||
V253_VLS_M,
|
||||
V253_VLS_MST,
|
||||
V253_VLS_S1,
|
||||
V253_VLS_S1T,
|
||||
V253_VLS_MS1T,
|
||||
V253_VLS_M1,
|
||||
V253_VLS_M1ST,
|
||||
V253_VLS_M1S1T,
|
||||
V253_VLS_H,
|
||||
V253_VLS_HT,
|
||||
V253_VLS_MS,
|
||||
V253_VLS_MS1,
|
||||
V253_VLS_M1S,
|
||||
V253_VLS_M1S1,
|
||||
V253_VLS_TEST,
|
||||
};
|
||||
|
||||
static int cx20442_pm_to_v253_vls(u8 value)
|
||||
{
|
||||
switch (value & ~(1 << CX20442_AGC)) {
|
||||
case 0:
|
||||
return V253_VLS_T;
|
||||
case (1 << CX20442_SPKOUT):
|
||||
case (1 << CX20442_MIC):
|
||||
case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
|
||||
return V253_VLS_M1S1;
|
||||
case (1 << CX20442_TELOUT):
|
||||
case (1 << CX20442_TELIN):
|
||||
case (1 << CX20442_TELOUT) | (1 << CX20442_TELIN):
|
||||
return V253_VLS_L;
|
||||
case (1 << CX20442_TELOUT) | (1 << CX20442_MIC):
|
||||
return V253_VLS_NONE;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
static int cx20442_pm_to_v253_vsp(u8 value)
|
||||
{
|
||||
switch (value & ~(1 << CX20442_AGC)) {
|
||||
case (1 << CX20442_SPKOUT):
|
||||
case (1 << CX20442_MIC):
|
||||
case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
|
||||
return (bool)(value & (1 << CX20442_AGC));
|
||||
}
|
||||
return (value & (1 << CX20442_AGC)) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
int vls, vsp, old, len;
|
||||
char buf[18];
|
||||
|
||||
if (reg >= codec->driver->reg_cache_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* hw_write and control_data pointers required for talking to the modem
|
||||
* are expected to be set by the line discipline initialization code */
|
||||
if (!codec->hw_write || !cx20442->control_data)
|
||||
return -EIO;
|
||||
|
||||
old = reg_cache[reg];
|
||||
reg_cache[reg] = value;
|
||||
|
||||
vls = cx20442_pm_to_v253_vls(value);
|
||||
if (vls < 0)
|
||||
return vls;
|
||||
|
||||
vsp = cx20442_pm_to_v253_vsp(value);
|
||||
if (vsp < 0)
|
||||
return vsp;
|
||||
|
||||
if ((vls == V253_VLS_T) ||
|
||||
(vls == cx20442_pm_to_v253_vls(old))) {
|
||||
if (vsp == cx20442_pm_to_v253_vsp(old))
|
||||
return 0;
|
||||
len = snprintf(buf, ARRAY_SIZE(buf), "at+vsp=%d\r", vsp);
|
||||
} else if (vsp == cx20442_pm_to_v253_vsp(old))
|
||||
len = snprintf(buf, ARRAY_SIZE(buf), "at+vls=%d\r", vls);
|
||||
else
|
||||
len = snprintf(buf, ARRAY_SIZE(buf),
|
||||
"at+vls=%d;+vsp=%d\r", vls, vsp);
|
||||
|
||||
if (unlikely(len > (ARRAY_SIZE(buf) - 1)))
|
||||
return -ENOMEM;
|
||||
|
||||
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
|
||||
if (codec->hw_write(cx20442->control_data, buf, len) != len)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Line discpline related code
|
||||
*
|
||||
* Any of the callback functions below can be used in two ways:
|
||||
* 1) registerd by a machine driver as one of line discipline operations,
|
||||
* 2) called from a machine's provided line discipline callback function
|
||||
* in case when extra machine specific code must be run as well.
|
||||
*/
|
||||
|
||||
/* Modem init: echo off, digital speaker off, quiet off, voice mode */
|
||||
static const char *v253_init = "ate0m0q0+fclass=8\r";
|
||||
|
||||
/* Line discipline .open() */
|
||||
static int v253_open(struct tty_struct *tty)
|
||||
{
|
||||
int ret, len = strlen(v253_init);
|
||||
|
||||
/* Doesn't make sense without write callback */
|
||||
if (!tty->ops->write)
|
||||
return -EINVAL;
|
||||
|
||||
/* Won't work if no codec pointer has been passed by a card driver */
|
||||
if (!tty->disc_data)
|
||||
return -ENODEV;
|
||||
|
||||
if (tty->ops->write(tty, v253_init, len) != len) {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
/* Actual setup will be performed after the modem responds. */
|
||||
return 0;
|
||||
err:
|
||||
tty->disc_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Line discipline .close() */
|
||||
static void v253_close(struct tty_struct *tty)
|
||||
{
|
||||
struct snd_soc_codec *codec = tty->disc_data;
|
||||
struct cx20442_priv *cx20442;
|
||||
|
||||
tty->disc_data = NULL;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Prevent the codec driver from further accessing the modem */
|
||||
codec->hw_write = NULL;
|
||||
cx20442->control_data = NULL;
|
||||
codec->component.card->pop_time = 0;
|
||||
}
|
||||
|
||||
/* Line discipline .hangup() */
|
||||
static int v253_hangup(struct tty_struct *tty)
|
||||
{
|
||||
v253_close(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Line discipline .receive_buf() */
|
||||
static void v253_receive(struct tty_struct *tty,
|
||||
const unsigned char *cp, char *fp, int count)
|
||||
{
|
||||
struct snd_soc_codec *codec = tty->disc_data;
|
||||
struct cx20442_priv *cx20442;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!cx20442->control_data) {
|
||||
/* First modem response, complete setup procedure */
|
||||
|
||||
/* Set up codec driver access to modem controls */
|
||||
cx20442->control_data = tty;
|
||||
codec->hw_write = (hw_write_t)tty->ops->write;
|
||||
codec->component.card->pop_time = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Line discipline .write_wakeup() */
|
||||
static void v253_wakeup(struct tty_struct *tty)
|
||||
{
|
||||
}
|
||||
|
||||
struct tty_ldisc_ops v253_ops = {
|
||||
.magic = TTY_LDISC_MAGIC,
|
||||
.name = "cx20442",
|
||||
.owner = THIS_MODULE,
|
||||
.open = v253_open,
|
||||
.close = v253_close,
|
||||
.hangup = v253_hangup,
|
||||
.receive_buf = v253_receive,
|
||||
.write_wakeup = v253_wakeup,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(v253_ops);
|
||||
|
||||
|
||||
/*
|
||||
* Codec DAI
|
||||
*/
|
||||
|
||||
static struct snd_soc_dai_driver cx20442_dai = {
|
||||
.name = "cx20442-voice",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_8000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
};
|
||||
|
||||
static int cx20442_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
int err = 0;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
|
||||
break;
|
||||
if (IS_ERR(cx20442->por))
|
||||
err = PTR_ERR(cx20442->por);
|
||||
else
|
||||
err = regulator_enable(cx20442->por);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
|
||||
break;
|
||||
if (IS_ERR(cx20442->por))
|
||||
err = PTR_ERR(cx20442->por);
|
||||
else
|
||||
err = regulator_disable(cx20442->por);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!err)
|
||||
codec->dapm.bias_level = level;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cx20442_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cx20442_priv *cx20442;
|
||||
|
||||
cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
|
||||
if (cx20442 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
cx20442->por = regulator_get(codec->dev, "POR");
|
||||
if (IS_ERR(cx20442->por))
|
||||
dev_warn(codec->dev, "failed to get the regulator");
|
||||
cx20442->control_data = NULL;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, cx20442);
|
||||
codec->hw_write = NULL;
|
||||
codec->component.card->pop_time = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int cx20442_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (cx20442->control_data) {
|
||||
struct tty_struct *tty = cx20442->control_data;
|
||||
tty_hangup(tty);
|
||||
}
|
||||
|
||||
if (!IS_ERR(cx20442->por)) {
|
||||
/* should be already in STANDBY, hence disabled */
|
||||
regulator_put(cx20442->por);
|
||||
}
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, NULL);
|
||||
kfree(cx20442);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u8 cx20442_reg;
|
||||
|
||||
static struct snd_soc_codec_driver cx20442_codec_dev = {
|
||||
.probe = cx20442_codec_probe,
|
||||
.remove = cx20442_codec_remove,
|
||||
.set_bias_level = cx20442_set_bias_level,
|
||||
.reg_cache_default = &cx20442_reg,
|
||||
.reg_cache_size = 1,
|
||||
.reg_word_size = sizeof(u8),
|
||||
.read = cx20442_read_reg_cache,
|
||||
.write = cx20442_write,
|
||||
.dapm_widgets = cx20442_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
|
||||
.dapm_routes = cx20442_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
|
||||
};
|
||||
|
||||
static int cx20442_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&cx20442_codec_dev, &cx20442_dai, 1);
|
||||
}
|
||||
|
||||
static int __exit cx20442_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cx20442_platform_driver = {
|
||||
.driver = {
|
||||
.name = "cx20442-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cx20442_platform_probe,
|
||||
.remove = __exit_p(cx20442_platform_remove),
|
||||
};
|
||||
|
||||
module_platform_driver(cx20442_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
|
||||
MODULE_AUTHOR("Janusz Krzysztofik");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:cx20442-codec");
|
||||
18
sound/soc/codecs/cx20442.h
Normal file
18
sound/soc/codecs/cx20442.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* cx20442.h -- audio driver for CX20442
|
||||
*
|
||||
* Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CX20442_CODEC_H
|
||||
#define _CX20442_CODEC_H
|
||||
|
||||
extern struct tty_ldisc_ops v253_ops;
|
||||
|
||||
#endif
|
||||
1384
sound/soc/codecs/da7210.c
Normal file
1384
sound/soc/codecs/da7210.c
Normal file
File diff suppressed because it is too large
Load diff
1600
sound/soc/codecs/da7213.c
Normal file
1600
sound/soc/codecs/da7213.c
Normal file
File diff suppressed because it is too large
Load diff
523
sound/soc/codecs/da7213.h
Normal file
523
sound/soc/codecs/da7213.h
Normal file
|
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
* da7213.h - DA7213 ASoC Codec Driver
|
||||
*
|
||||
* Copyright (c) 2013 Dialog Semiconductor
|
||||
*
|
||||
* Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _DA7213_H
|
||||
#define _DA7213_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/da7213.h>
|
||||
|
||||
/*
|
||||
* Registers
|
||||
*/
|
||||
|
||||
/* Status Registers */
|
||||
#define DA7213_STATUS1 0x02
|
||||
#define DA7213_PLL_STATUS 0x03
|
||||
#define DA7213_AUX_L_GAIN_STATUS 0x04
|
||||
#define DA7213_AUX_R_GAIN_STATUS 0x05
|
||||
#define DA7213_MIC_1_GAIN_STATUS 0x06
|
||||
#define DA7213_MIC_2_GAIN_STATUS 0x07
|
||||
#define DA7213_MIXIN_L_GAIN_STATUS 0x08
|
||||
#define DA7213_MIXIN_R_GAIN_STATUS 0x09
|
||||
#define DA7213_ADC_L_GAIN_STATUS 0x0A
|
||||
#define DA7213_ADC_R_GAIN_STATUS 0x0B
|
||||
#define DA7213_DAC_L_GAIN_STATUS 0x0C
|
||||
#define DA7213_DAC_R_GAIN_STATUS 0x0D
|
||||
#define DA7213_HP_L_GAIN_STATUS 0x0E
|
||||
#define DA7213_HP_R_GAIN_STATUS 0x0F
|
||||
#define DA7213_LINE_GAIN_STATUS 0x10
|
||||
|
||||
/* System Initialisation Registers */
|
||||
#define DA7213_DIG_ROUTING_DAI 0x21
|
||||
#define DA7213_SR 0x22
|
||||
#define DA7213_REFERENCES 0x23
|
||||
#define DA7213_PLL_FRAC_TOP 0x24
|
||||
#define DA7213_PLL_FRAC_BOT 0x25
|
||||
#define DA7213_PLL_INTEGER 0x26
|
||||
#define DA7213_PLL_CTRL 0x27
|
||||
#define DA7213_DAI_CLK_MODE 0x28
|
||||
#define DA7213_DAI_CTRL 0x29
|
||||
#define DA7213_DIG_ROUTING_DAC 0x2A
|
||||
#define DA7213_ALC_CTRL1 0x2B
|
||||
|
||||
/* Input - Gain, Select and Filter Registers */
|
||||
#define DA7213_AUX_L_GAIN 0x30
|
||||
#define DA7213_AUX_R_GAIN 0x31
|
||||
#define DA7213_MIXIN_L_SELECT 0x32
|
||||
#define DA7213_MIXIN_R_SELECT 0x33
|
||||
#define DA7213_MIXIN_L_GAIN 0x34
|
||||
#define DA7213_MIXIN_R_GAIN 0x35
|
||||
#define DA7213_ADC_L_GAIN 0x36
|
||||
#define DA7213_ADC_R_GAIN 0x37
|
||||
#define DA7213_ADC_FILTERS1 0x38
|
||||
#define DA7213_MIC_1_GAIN 0x39
|
||||
#define DA7213_MIC_2_GAIN 0x3A
|
||||
|
||||
/* Output - Gain, Select and Filter Registers */
|
||||
#define DA7213_DAC_FILTERS5 0x40
|
||||
#define DA7213_DAC_FILTERS2 0x41
|
||||
#define DA7213_DAC_FILTERS3 0x42
|
||||
#define DA7213_DAC_FILTERS4 0x43
|
||||
#define DA7213_DAC_FILTERS1 0x44
|
||||
#define DA7213_DAC_L_GAIN 0x45
|
||||
#define DA7213_DAC_R_GAIN 0x46
|
||||
#define DA7213_CP_CTRL 0x47
|
||||
#define DA7213_HP_L_GAIN 0x48
|
||||
#define DA7213_HP_R_GAIN 0x49
|
||||
#define DA7213_LINE_GAIN 0x4A
|
||||
#define DA7213_MIXOUT_L_SELECT 0x4B
|
||||
#define DA7213_MIXOUT_R_SELECT 0x4C
|
||||
|
||||
/* System Controller Registers */
|
||||
#define DA7213_SYSTEM_MODES_INPUT 0x50
|
||||
#define DA7213_SYSTEM_MODES_OUTPUT 0x51
|
||||
|
||||
/* Control Registers */
|
||||
#define DA7213_AUX_L_CTRL 0x60
|
||||
#define DA7213_AUX_R_CTRL 0x61
|
||||
#define DA7213_MICBIAS_CTRL 0x62
|
||||
#define DA7213_MIC_1_CTRL 0x63
|
||||
#define DA7213_MIC_2_CTRL 0x64
|
||||
#define DA7213_MIXIN_L_CTRL 0x65
|
||||
#define DA7213_MIXIN_R_CTRL 0x66
|
||||
#define DA7213_ADC_L_CTRL 0x67
|
||||
#define DA7213_ADC_R_CTRL 0x68
|
||||
#define DA7213_DAC_L_CTRL 0x69
|
||||
#define DA7213_DAC_R_CTRL 0x6A
|
||||
#define DA7213_HP_L_CTRL 0x6B
|
||||
#define DA7213_HP_R_CTRL 0x6C
|
||||
#define DA7213_LINE_CTRL 0x6D
|
||||
#define DA7213_MIXOUT_L_CTRL 0x6E
|
||||
#define DA7213_MIXOUT_R_CTRL 0x6F
|
||||
|
||||
/* Configuration Registers */
|
||||
#define DA7213_LDO_CTRL 0x90
|
||||
#define DA7213_IO_CTRL 0x91
|
||||
#define DA7213_GAIN_RAMP_CTRL 0x92
|
||||
#define DA7213_MIC_CONFIG 0x93
|
||||
#define DA7213_PC_COUNT 0x94
|
||||
#define DA7213_CP_VOL_THRESHOLD1 0x95
|
||||
#define DA7213_CP_DELAY 0x96
|
||||
#define DA7213_CP_DETECTOR 0x97
|
||||
#define DA7213_DAI_OFFSET 0x98
|
||||
#define DA7213_DIG_CTRL 0x99
|
||||
#define DA7213_ALC_CTRL2 0x9A
|
||||
#define DA7213_ALC_CTRL3 0x9B
|
||||
#define DA7213_ALC_NOISE 0x9C
|
||||
#define DA7213_ALC_TARGET_MIN 0x9D
|
||||
#define DA7213_ALC_TARGET_MAX 0x9E
|
||||
#define DA7213_ALC_GAIN_LIMITS 0x9F
|
||||
#define DA7213_ALC_ANA_GAIN_LIMITS 0xA0
|
||||
#define DA7213_ALC_ANTICLIP_CTRL 0xA1
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL 0xA2
|
||||
|
||||
#define DA7213_ALC_OFFSET_AUTO_M_L 0xA3
|
||||
#define DA7213_ALC_OFFSET_AUTO_U_L 0xA4
|
||||
#define DA7213_ALC_OFFSET_MAN_M_L 0xA6
|
||||
#define DA7213_ALC_OFFSET_MAN_U_L 0xA7
|
||||
#define DA7213_ALC_OFFSET_AUTO_M_R 0xA8
|
||||
#define DA7213_ALC_OFFSET_AUTO_U_R 0xA9
|
||||
#define DA7213_ALC_OFFSET_MAN_M_R 0xAB
|
||||
#define DA7213_ALC_OFFSET_MAN_U_R 0xAC
|
||||
#define DA7213_ALC_CIC_OP_LVL_CTRL 0xAD
|
||||
#define DA7213_ALC_CIC_OP_LVL_DATA 0xAE
|
||||
#define DA7213_DAC_NG_SETUP_TIME 0xAF
|
||||
#define DA7213_DAC_NG_OFF_THRESHOLD 0xB0
|
||||
#define DA7213_DAC_NG_ON_THRESHOLD 0xB1
|
||||
#define DA7213_DAC_NG_CTRL 0xB2
|
||||
|
||||
|
||||
/*
|
||||
* Bit fields
|
||||
*/
|
||||
|
||||
/* DA7213_SR = 0x22 */
|
||||
#define DA7213_SR_8000 (0x1 << 0)
|
||||
#define DA7213_SR_11025 (0x2 << 0)
|
||||
#define DA7213_SR_12000 (0x3 << 0)
|
||||
#define DA7213_SR_16000 (0x5 << 0)
|
||||
#define DA7213_SR_22050 (0x6 << 0)
|
||||
#define DA7213_SR_24000 (0x7 << 0)
|
||||
#define DA7213_SR_32000 (0x9 << 0)
|
||||
#define DA7213_SR_44100 (0xA << 0)
|
||||
#define DA7213_SR_48000 (0xB << 0)
|
||||
#define DA7213_SR_88200 (0xE << 0)
|
||||
#define DA7213_SR_96000 (0xF << 0)
|
||||
|
||||
/* DA7213_REFERENCES = 0x23 */
|
||||
#define DA7213_BIAS_EN (0x1 << 3)
|
||||
#define DA7213_VMID_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_PLL_CTRL = 0x27 */
|
||||
#define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2)
|
||||
#define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2)
|
||||
#define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2)
|
||||
#define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2)
|
||||
#define DA7213_PLL_INDIV_MASK (0x3 << 2)
|
||||
#define DA7213_PLL_MCLK_SQR_EN (0x1 << 4)
|
||||
#define DA7213_PLL_32K_MODE (0x1 << 5)
|
||||
#define DA7213_PLL_SRM_EN (0x1 << 6)
|
||||
#define DA7213_PLL_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_DAI_CLK_MODE = 0x28 */
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_64 (0x1 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_128 (0x2 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
|
||||
#define DA7213_DAI_CLK_POL_INV (0x1 << 2)
|
||||
#define DA7213_DAI_WCLK_POL_INV (0x1 << 3)
|
||||
#define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7)
|
||||
#define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7)
|
||||
#define DA7213_DAI_CLK_EN_MASK (0x1 << 7)
|
||||
|
||||
/* DA7213_DAI_CTRL = 0x29 */
|
||||
#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0)
|
||||
#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0)
|
||||
#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0)
|
||||
#define DA7213_DAI_FORMAT_MASK (0x3 << 0)
|
||||
#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2)
|
||||
#define DA7213_DAI_EN_SHIFT 7
|
||||
|
||||
/* DA7213_DIG_ROUTING_DAI = 0x21 */
|
||||
#define DA7213_DAI_L_SRC_SHIFT 0
|
||||
#define DA7213_DAI_R_SRC_SHIFT 4
|
||||
#define DA7213_DAI_SRC_MAX 4
|
||||
|
||||
/* DA7213_DIG_ROUTING_DAC = 0x2A */
|
||||
#define DA7213_DAC_L_SRC_SHIFT 0
|
||||
#define DA7213_DAC_L_MONO_SHIFT 3
|
||||
#define DA7213_DAC_R_SRC_SHIFT 4
|
||||
#define DA7213_DAC_R_MONO_SHIFT 7
|
||||
#define DA7213_DAC_SRC_MAX 4
|
||||
#define DA7213_DAC_MONO_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_CTRL1 = 0x2B */
|
||||
#define DA7213_ALC_OFFSET_EN_SHIFT 0
|
||||
#define DA7213_ALC_OFFSET_EN_MAX 0x1
|
||||
#define DA7213_ALC_OFFSET_EN (0x1 << 0)
|
||||
#define DA7213_ALC_SYNC_MODE (0x1 << 1)
|
||||
#define DA7213_ALC_CALIB_MODE_MAN (0x1 << 2)
|
||||
#define DA7213_ALC_L_EN_SHIFT 3
|
||||
#define DA7213_ALC_AUTO_CALIB_EN (0x1 << 4)
|
||||
#define DA7213_ALC_CALIB_OVERFLOW (0x1 << 5)
|
||||
#define DA7213_ALC_R_EN_SHIFT 7
|
||||
#define DA7213_ALC_EN_MAX 0x1
|
||||
|
||||
/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */
|
||||
#define DA7213_AUX_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_AUX_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */
|
||||
#define DA7213_DMIC_EN_SHIFT 7
|
||||
#define DA7213_DMIC_EN_MAX 0x1
|
||||
|
||||
/* DA7213_MIXIN_L_SELECT = 0x32 */
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT 0
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT 1
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1 (0x1 << 1)
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT 2
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2 (0x1 << 2)
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT 3
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MAX 0x1
|
||||
|
||||
/* DA7213_MIXIN_R_SELECT = 0x33 */
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT 0
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT 1
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2 (0x1 << 1)
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT 2
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1 (0x1 << 2)
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT 3
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MAX 0x1
|
||||
#define DA7213_MIC_BIAS_OUTPUT_SELECT_2 (0x1 << 6)
|
||||
|
||||
/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */
|
||||
#define DA7213_MIXIN_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_MIXIN_AMP_GAIN_MAX 0xF
|
||||
|
||||
/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */
|
||||
#define DA7213_ADC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_ADC_AMP_GAIN_MAX 0x7F
|
||||
|
||||
/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */
|
||||
#define DA7213_VOICE_HPF_CORNER_SHIFT 0
|
||||
#define DA7213_VOICE_HPF_CORNER_MAX 8
|
||||
#define DA7213_VOICE_EN_SHIFT 3
|
||||
#define DA7213_VOICE_EN_MAX 0x1
|
||||
#define DA7213_AUDIO_HPF_CORNER_SHIFT 4
|
||||
#define DA7213_AUDIO_HPF_CORNER_MAX 4
|
||||
#define DA7213_HPF_EN_SHIFT 7
|
||||
#define DA7213_HPF_EN_MAX 0x1
|
||||
|
||||
/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */
|
||||
#define DA7213_MIC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_MIC_AMP_GAIN_MAX 0x7
|
||||
|
||||
/* DA7213_DAC_FILTERS5 = 0x40 */
|
||||
#define DA7213_DAC_SOFTMUTE_EN_SHIFT 7
|
||||
#define DA7213_DAC_SOFTMUTE_EN_MAX 0x1
|
||||
#define DA7213_DAC_SOFTMUTE_RATE_SHIFT 4
|
||||
#define DA7213_DAC_SOFTMUTE_RATE_MAX 7
|
||||
|
||||
/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */
|
||||
#define DA7213_DAC_EQ_BAND_MAX 0xF
|
||||
|
||||
/* DA7213_DAC_FILTERS2 = 0x41 */
|
||||
#define DA7213_DAC_EQ_BAND1_SHIFT 0
|
||||
#define DA7213_DAC_EQ_BAND2_SHIFT 4
|
||||
|
||||
/* DA7213_DAC_FILTERS2 = 0x42 */
|
||||
#define DA7213_DAC_EQ_BAND3_SHIFT 0
|
||||
#define DA7213_DAC_EQ_BAND4_SHIFT 4
|
||||
|
||||
/* DA7213_DAC_FILTERS4 = 0x43 */
|
||||
#define DA7213_DAC_EQ_BAND5_SHIFT 0
|
||||
#define DA7213_DAC_EQ_EN_SHIFT 7
|
||||
#define DA7213_DAC_EQ_EN_MAX 0x1
|
||||
|
||||
/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */
|
||||
#define DA7213_DAC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_DAC_AMP_GAIN_MAX 0x7F
|
||||
|
||||
/* DA7213_HP_L/R_GAIN = 0x45/0x46 */
|
||||
#define DA7213_HP_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_HP_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_CP_CTRL = 0x47 */
|
||||
#define DA7213_CP_EN_SHIFT 7
|
||||
|
||||
/* DA7213_LINE_GAIN = 0x4A */
|
||||
#define DA7213_LINE_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_LINE_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_MIXOUT_L_SELECT = 0x4B */
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT 0
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT 1
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT 2
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT 3
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT 4
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 5
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 6
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MAX 0x1
|
||||
|
||||
/* DA7213_MIXOUT_R_SELECT = 0x4C */
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT 0
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT 1
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT 2
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT 3
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT 4
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 5
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 6
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MAX 0x1
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_MUTE_EN_SHIFT 6
|
||||
#define DA7213_MUTE_EN_MAX 0x1
|
||||
#define DA7213_MUTE_EN (0x1 << 6)
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_GAIN_RAMP_EN_SHIFT 5
|
||||
#define DA7213_GAIN_RAMP_EN_MAX 0x1
|
||||
#define DA7213_GAIN_RAMP_EN (0x1 << 5)
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_ZC_EN_SHIFT 4
|
||||
#define DA7213_ZC_EN_MAX 0x1
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_AMP_EN_SHIFT 7
|
||||
|
||||
/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */
|
||||
#define DA7213_MIC_AMP_IN_SEL_SHIFT 2
|
||||
#define DA7213_MIC_AMP_IN_SEL_MAX 3
|
||||
|
||||
/* DA7213_MICBIAS_CTRL = 0x62 */
|
||||
#define DA7213_MICBIAS1_LEVEL_SHIFT 0
|
||||
#define DA7213_MICBIAS1_LEVEL_MASK (0x3 << 0)
|
||||
#define DA7213_MICBIAS1_EN_SHIFT 3
|
||||
#define DA7213_MICBIAS2_LEVEL_SHIFT 4
|
||||
#define DA7213_MICBIAS2_LEVEL_MASK (0x3 << 4)
|
||||
#define DA7213_MICBIAS2_EN_SHIFT 7
|
||||
|
||||
/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */
|
||||
#define DA7213_MIXIN_MIX_EN (0x1 << 3)
|
||||
|
||||
/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */
|
||||
#define DA7213_ADC_EN_SHIFT 7
|
||||
#define DA7213_ADC_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_DAC_L/R_CTRL = 0x69/0x6A*/
|
||||
#define DA7213_DAC_EN_SHIFT 7
|
||||
|
||||
/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */
|
||||
#define DA7213_HP_AMP_OE (0x1 << 3)
|
||||
|
||||
/* DA7213_LINE_CTRL = 0x6D */
|
||||
#define DA7213_LINE_AMP_OE (0x1 << 3)
|
||||
|
||||
/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */
|
||||
#define DA7213_MIXOUT_MIX_EN (0x1 << 3)
|
||||
|
||||
/* DA7213_GAIN_RAMP_CTRL = 0x92 */
|
||||
#define DA7213_GAIN_RAMP_RATE_SHIFT 0
|
||||
#define DA7213_GAIN_RAMP_RATE_MAX 4
|
||||
|
||||
/* DA7213_MIC_CONFIG = 0x93 */
|
||||
#define DA7213_DMIC_DATA_SEL_SHIFT 0
|
||||
#define DA7213_DMIC_DATA_SEL_MASK (0x1 << 0)
|
||||
#define DA7213_DMIC_SAMPLEPHASE_SHIFT 1
|
||||
#define DA7213_DMIC_SAMPLEPHASE_MASK (0x1 << 1)
|
||||
#define DA7213_DMIC_CLK_RATE_SHIFT 2
|
||||
#define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2)
|
||||
|
||||
/* DA7213_DIG_CTRL = 0x99 */
|
||||
#define DA7213_DAC_L_INV_SHIFT 3
|
||||
#define DA7213_DAC_R_INV_SHIFT 7
|
||||
#define DA7213_DAC_INV_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_CTRL2 = 0x9A */
|
||||
#define DA7213_ALC_ATTACK_SHIFT 0
|
||||
#define DA7213_ALC_ATTACK_MAX 13
|
||||
#define DA7213_ALC_RELEASE_SHIFT 4
|
||||
#define DA7213_ALC_RELEASE_MAX 11
|
||||
|
||||
/* DA7213_ALC_CTRL3 = 0x9B */
|
||||
#define DA7213_ALC_HOLD_SHIFT 0
|
||||
#define DA7213_ALC_HOLD_MAX 16
|
||||
#define DA7213_ALC_INTEG_ATTACK_SHIFT 4
|
||||
#define DA7213_ALC_INTEG_RELEASE_SHIFT 6
|
||||
#define DA7213_ALC_INTEG_MAX 4
|
||||
|
||||
/*
|
||||
* DA7213_ALC_NOISE = 0x9C,
|
||||
* DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E
|
||||
*/
|
||||
#define DA7213_ALC_THRESHOLD_SHIFT 0
|
||||
#define DA7213_ALC_THRESHOLD_MAX 0x3F
|
||||
|
||||
/* DA7213_ALC_GAIN_LIMITS = 0x9F */
|
||||
#define DA7213_ALC_ATTEN_MAX_SHIFT 0
|
||||
#define DA7213_ALC_GAIN_MAX_SHIFT 4
|
||||
#define DA7213_ALC_ATTEN_GAIN_MAX_MAX 0xF
|
||||
|
||||
/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */
|
||||
#define DA7213_ALC_ANA_GAIN_MIN_SHIFT 0
|
||||
#define DA7213_ALC_ANA_GAIN_MAX_SHIFT 4
|
||||
#define DA7213_ALC_ANA_GAIN_MAX 0x7
|
||||
|
||||
/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */
|
||||
#define DA7213_ALC_ANTICLIP_EN_SHIFT 7
|
||||
#define DA7213_ALC_ANTICLIP_EN_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT 0
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL_MAX 0x7F
|
||||
|
||||
/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */
|
||||
#define DA7213_ALC_DATA_MIDDLE (0x2 << 0)
|
||||
#define DA7213_ALC_DATA_TOP (0x3 << 0)
|
||||
#define DA7213_ALC_CIC_OP_CHANNEL_LEFT (0x0 << 7)
|
||||
#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT (0x1 << 7)
|
||||
|
||||
/* DA7213_DAC_NG_SETUP_TIME = 0xAF */
|
||||
#define DA7213_DAC_NG_SETUP_TIME_SHIFT 0
|
||||
#define DA7213_DAC_NG_SETUP_TIME_MAX 4
|
||||
#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT 2
|
||||
#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT 3
|
||||
#define DA7213_DAC_NG_RAMP_RATE_MAX 2
|
||||
|
||||
/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */
|
||||
#define DA7213_DAC_NG_THRESHOLD_SHIFT 0
|
||||
#define DA7213_DAC_NG_THRESHOLD_MAX 0x7
|
||||
|
||||
/* DA7213_DAC_NG_CTRL = 0xB2 */
|
||||
#define DA7213_DAC_NG_EN_SHIFT 7
|
||||
#define DA7213_DAC_NG_EN_MAX 0x1
|
||||
|
||||
|
||||
/*
|
||||
* General defines
|
||||
*/
|
||||
|
||||
/* Register inversion */
|
||||
#define DA7213_NO_INVERT 0
|
||||
#define DA7213_INVERT 1
|
||||
|
||||
/* Byte related defines */
|
||||
#define DA7213_BYTE_SHIFT 8
|
||||
#define DA7213_BYTE_MASK 0xFF
|
||||
|
||||
/* ALC related */
|
||||
#define DA7213_ALC_OFFSET_15_8 0x00FF00
|
||||
#define DA7213_ALC_OFFSET_19_16 0x0F0000
|
||||
#define DA7213_ALC_AVG_ITERATIONS 5
|
||||
|
||||
/* PLL related */
|
||||
#define DA7213_SYSCLK_MCLK 0
|
||||
#define DA7213_SYSCLK_PLL 1
|
||||
#define DA7213_PLL_FREQ_OUT_90316800 90316800
|
||||
#define DA7213_PLL_FREQ_OUT_98304000 98304000
|
||||
#define DA7213_PLL_FREQ_OUT_94310400 94310400
|
||||
#define DA7213_PLL_INDIV_5_10_MHZ_VAL 2
|
||||
#define DA7213_PLL_INDIV_10_20_MHZ_VAL 4
|
||||
#define DA7213_PLL_INDIV_20_40_MHZ_VAL 8
|
||||
#define DA7213_PLL_INDIV_40_54_MHZ_VAL 16
|
||||
|
||||
enum clk_src {
|
||||
DA7213_CLKSRC_MCLK
|
||||
};
|
||||
|
||||
/* Codec private data */
|
||||
struct da7213_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int mclk_rate;
|
||||
bool master;
|
||||
bool mclk_squarer_en;
|
||||
bool srm_en;
|
||||
bool alc_calib_auto;
|
||||
bool alc_en;
|
||||
struct da7213_platform_data *pdata;
|
||||
};
|
||||
|
||||
#endif /* _DA7213_H */
|
||||
1589
sound/soc/codecs/da732x.c
Normal file
1589
sound/soc/codecs/da732x.c
Normal file
File diff suppressed because it is too large
Load diff
130
sound/soc/codecs/da732x.h
Normal file
130
sound/soc/codecs/da732x.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File
|
||||
*
|
||||
* Copyright (C) 2012 Dialog Semiconductor GmbH
|
||||
*
|
||||
* Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DA732X_H_
|
||||
#define __DA732X_H_
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
/* General */
|
||||
#define DA732X_U8_MASK 0xFF
|
||||
#define DA732X_4BYTES 4
|
||||
#define DA732X_3BYTES 3
|
||||
#define DA732X_2BYTES 2
|
||||
#define DA732X_1BYTE 1
|
||||
#define DA732X_1BYTE_SHIFT 8
|
||||
#define DA732X_2BYTES_SHIFT 16
|
||||
#define DA732X_3BYTES_SHIFT 24
|
||||
#define DA732X_4BYTES_SHIFT 32
|
||||
|
||||
#define DA732X_DACS_DIS 0x0
|
||||
#define DA732X_HP_DIS 0x0
|
||||
#define DA732X_CLEAR_REG 0x0
|
||||
|
||||
/* Calibration */
|
||||
#define DA732X_DAC_OFFSET_STEP 0x20
|
||||
#define DA732X_OUTPUT_OFFSET_STEP 0x80
|
||||
#define DA732X_HP_OUT_TRIM_VAL 0x0
|
||||
#define DA732X_WAIT_FOR_STABILIZATION 1
|
||||
#define DA732X_HPL_DAC 0
|
||||
#define DA732X_HPR_DAC 1
|
||||
#define DA732X_HP_DACS 2
|
||||
#define DA732X_HPL_AMP 0
|
||||
#define DA732X_HPR_AMP 1
|
||||
#define DA732X_HP_AMPS 2
|
||||
|
||||
/* Clock settings */
|
||||
#define DA732X_STARTUP_DELAY 100
|
||||
#define DA732X_PLL_OUT_196608 196608000
|
||||
#define DA732X_PLL_OUT_180634 180633600
|
||||
#define DA732X_PLL_OUT_SRM 188620800
|
||||
#define DA732X_MCLK_10MHZ 10000000
|
||||
#define DA732X_MCLK_20MHZ 20000000
|
||||
#define DA732X_MCLK_40MHZ 40000000
|
||||
#define DA732X_MCLK_54MHZ 54000000
|
||||
#define DA732X_MCLK_RET_0_10MHZ 0
|
||||
#define DA732X_MCLK_VAL_0_10MHZ 1
|
||||
#define DA732X_MCLK_RET_10_20MHZ 1
|
||||
#define DA732X_MCLK_VAL_10_20MHZ 2
|
||||
#define DA732X_MCLK_RET_20_40MHZ 2
|
||||
#define DA732X_MCLK_VAL_20_40MHZ 4
|
||||
#define DA732X_MCLK_RET_40_54MHZ 3
|
||||
#define DA732X_MCLK_VAL_40_54MHZ 8
|
||||
#define DA732X_DAI_ID1 0
|
||||
#define DA732X_DAI_ID2 1
|
||||
#define DA732X_SRCCLK_PLL 0
|
||||
#define DA732X_SRCCLK_MCLK 1
|
||||
|
||||
#define DA732X_LIN_LP_VOL 0x4F
|
||||
#define DA732X_LP_VOL 0x40
|
||||
|
||||
/* Kcontrols */
|
||||
#define DA732X_DAC_EN_MAX 2
|
||||
#define DA732X_ADCL_MUX_MAX 2
|
||||
#define DA732X_ADCR_MUX_MAX 3
|
||||
#define DA732X_HPF_MODE_MAX 3
|
||||
#define DA732X_HPF_MODE_SHIFT 4
|
||||
#define DA732X_HPF_MUSIC_SHIFT 0
|
||||
#define DA732X_HPF_MUSIC_MAX 4
|
||||
#define DA732X_HPF_VOICE_SHIFT 4
|
||||
#define DA732X_HPF_VOICE_MAX 8
|
||||
#define DA732X_EQ_EN_MAX 1
|
||||
#define DA732X_HPF_VOICE 1
|
||||
#define DA732X_HPF_MUSIC 2
|
||||
#define DA732X_HPF_DISABLED 0
|
||||
#define DA732X_NO_INVERT 0
|
||||
#define DA732X_INVERT 1
|
||||
#define DA732X_SWITCH_MAX 1
|
||||
#define DA732X_ENABLE_CP 1
|
||||
#define DA732X_DISABLE_CP 0
|
||||
#define DA732X_DISABLE_ALL_CLKS 0
|
||||
#define DA732X_RESET_ADCS 0
|
||||
|
||||
/* dB values */
|
||||
#define DA732X_MIC_VOL_DB_MIN 0
|
||||
#define DA732X_MIC_VOL_DB_INC 50
|
||||
#define DA732X_MIC_PRE_VOL_DB_MIN 0
|
||||
#define DA732X_MIC_PRE_VOL_DB_INC 600
|
||||
#define DA732X_AUX_VOL_DB_MIN -6000
|
||||
#define DA732X_AUX_VOL_DB_INC 150
|
||||
#define DA732X_HP_VOL_DB_MIN -2250
|
||||
#define DA732X_HP_VOL_DB_INC 150
|
||||
#define DA732X_LIN2_VOL_DB_MIN -1650
|
||||
#define DA732X_LIN2_VOL_DB_INC 150
|
||||
#define DA732X_LIN3_VOL_DB_MIN -1650
|
||||
#define DA732X_LIN3_VOL_DB_INC 150
|
||||
#define DA732X_LIN4_VOL_DB_MIN -2250
|
||||
#define DA732X_LIN4_VOL_DB_INC 150
|
||||
#define DA732X_EQ_BAND_VOL_DB_MIN -1050
|
||||
#define DA732X_EQ_BAND_VOL_DB_INC 150
|
||||
#define DA732X_DAC_VOL_DB_MIN -7725
|
||||
#define DA732X_DAC_VOL_DB_INC 75
|
||||
#define DA732X_ADC_VOL_DB_MIN 0
|
||||
#define DA732X_ADC_VOL_DB_INC -1
|
||||
#define DA732X_EQ_OVERALL_VOL_DB_MIN -1800
|
||||
#define DA732X_EQ_OVERALL_VOL_DB_INC 600
|
||||
|
||||
enum da732x_sysctl {
|
||||
DA732X_SR_8KHZ = 0x1,
|
||||
DA732X_SR_11_025KHZ = 0x2,
|
||||
DA732X_SR_12KHZ = 0x3,
|
||||
DA732X_SR_16KHZ = 0x5,
|
||||
DA732X_SR_22_05KHZ = 0x6,
|
||||
DA732X_SR_24KHZ = 0x7,
|
||||
DA732X_SR_32KHZ = 0x9,
|
||||
DA732X_SR_44_1KHZ = 0xA,
|
||||
DA732X_SR_48KHZ = 0xB,
|
||||
DA732X_SR_88_1KHZ = 0xE,
|
||||
DA732X_SR_96KHZ = 0xF,
|
||||
};
|
||||
|
||||
#endif /* __DA732X_H_ */
|
||||
654
sound/soc/codecs/da732x_reg.h
Normal file
654
sound/soc/codecs/da732x_reg.h
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
/*
|
||||
* da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File
|
||||
*
|
||||
* Copyright (C) 2012 Dialog Semiconductor GmbH
|
||||
*
|
||||
* Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DA732X_REG_H_
|
||||
#define __DA732X_REG_H_
|
||||
|
||||
/* DA732X registers */
|
||||
#define DA732X_REG_STATUS_EXT 0x00
|
||||
#define DA732X_REG_STATUS 0x01
|
||||
#define DA732X_REG_REF1 0x02
|
||||
#define DA732X_REG_BIAS_EN 0x03
|
||||
#define DA732X_REG_BIAS1 0x04
|
||||
#define DA732X_REG_BIAS2 0x05
|
||||
#define DA732X_REG_BIAS3 0x06
|
||||
#define DA732X_REG_BIAS4 0x07
|
||||
#define DA732X_REG_MICBIAS2 0x0F
|
||||
#define DA732X_REG_MICBIAS1 0x10
|
||||
#define DA732X_REG_MICDET 0x11
|
||||
#define DA732X_REG_MIC1_PRE 0x12
|
||||
#define DA732X_REG_MIC1 0x13
|
||||
#define DA732X_REG_MIC2_PRE 0x14
|
||||
#define DA732X_REG_MIC2 0x15
|
||||
#define DA732X_REG_AUX1L 0x16
|
||||
#define DA732X_REG_AUX1R 0x17
|
||||
#define DA732X_REG_MIC3_PRE 0x18
|
||||
#define DA732X_REG_MIC3 0x19
|
||||
#define DA732X_REG_INP_PINBIAS 0x1A
|
||||
#define DA732X_REG_INP_ZC_EN 0x1B
|
||||
#define DA732X_REG_INP_MUX 0x1D
|
||||
#define DA732X_REG_HP_DET 0x20
|
||||
#define DA732X_REG_HPL_DAC_OFFSET 0x21
|
||||
#define DA732X_REG_HPL_DAC_OFF_CNTL 0x22
|
||||
#define DA732X_REG_HPL_OUT_OFFSET 0x23
|
||||
#define DA732X_REG_HPL 0x24
|
||||
#define DA732X_REG_HPL_VOL 0x25
|
||||
#define DA732X_REG_HPR_DAC_OFFSET 0x26
|
||||
#define DA732X_REG_HPR_DAC_OFF_CNTL 0x27
|
||||
#define DA732X_REG_HPR_OUT_OFFSET 0x28
|
||||
#define DA732X_REG_HPR 0x29
|
||||
#define DA732X_REG_HPR_VOL 0x2A
|
||||
#define DA732X_REG_LIN2 0x2B
|
||||
#define DA732X_REG_LIN3 0x2C
|
||||
#define DA732X_REG_LIN4 0x2D
|
||||
#define DA732X_REG_OUT_ZC_EN 0x2E
|
||||
#define DA732X_REG_HP_LIN1_GNDSEL 0x37
|
||||
#define DA732X_REG_CP_HP1 0x3A
|
||||
#define DA732X_REG_CP_HP2 0x3B
|
||||
#define DA732X_REG_CP_CTRL1 0x40
|
||||
#define DA732X_REG_CP_CTRL2 0x41
|
||||
#define DA732X_REG_CP_CTRL3 0x42
|
||||
#define DA732X_REG_CP_LEVEL_MASK 0x43
|
||||
#define DA732X_REG_CP_DET 0x44
|
||||
#define DA732X_REG_CP_STATUS 0x45
|
||||
#define DA732X_REG_CP_THRESH1 0x46
|
||||
#define DA732X_REG_CP_THRESH2 0x47
|
||||
#define DA732X_REG_CP_THRESH3 0x48
|
||||
#define DA732X_REG_CP_THRESH4 0x49
|
||||
#define DA732X_REG_CP_THRESH5 0x4A
|
||||
#define DA732X_REG_CP_THRESH6 0x4B
|
||||
#define DA732X_REG_CP_THRESH7 0x4C
|
||||
#define DA732X_REG_CP_THRESH8 0x4D
|
||||
#define DA732X_REG_PLL_DIV_LO 0x50
|
||||
#define DA732X_REG_PLL_DIV_MID 0x51
|
||||
#define DA732X_REG_PLL_DIV_HI 0x52
|
||||
#define DA732X_REG_PLL_CTRL 0x53
|
||||
#define DA732X_REG_CLK_CTRL 0x54
|
||||
#define DA732X_REG_CLK_DSP 0x5A
|
||||
#define DA732X_REG_CLK_EN1 0x5B
|
||||
#define DA732X_REG_CLK_EN2 0x5C
|
||||
#define DA732X_REG_CLK_EN3 0x5D
|
||||
#define DA732X_REG_CLK_EN4 0x5E
|
||||
#define DA732X_REG_CLK_EN5 0x5F
|
||||
#define DA732X_REG_AIF_MCLK 0x60
|
||||
#define DA732X_REG_AIFA1 0x61
|
||||
#define DA732X_REG_AIFA2 0x62
|
||||
#define DA732X_REG_AIFA3 0x63
|
||||
#define DA732X_REG_AIFB1 0x64
|
||||
#define DA732X_REG_AIFB2 0x65
|
||||
#define DA732X_REG_AIFB3 0x66
|
||||
#define DA732X_REG_PC_CTRL 0x6A
|
||||
#define DA732X_REG_DATA_ROUTE 0x70
|
||||
#define DA732X_REG_DSP_CTRL 0x71
|
||||
#define DA732X_REG_CIF_CTRL2 0x74
|
||||
#define DA732X_REG_HANDSHAKE 0x75
|
||||
#define DA732X_REG_MBOX0 0x76
|
||||
#define DA732X_REG_MBOX1 0x77
|
||||
#define DA732X_REG_MBOX2 0x78
|
||||
#define DA732X_REG_MBOX_STATUS 0x79
|
||||
#define DA732X_REG_SPARE1_OUT 0x7D
|
||||
#define DA732X_REG_SPARE2_OUT 0x7E
|
||||
#define DA732X_REG_SPARE1_IN 0x7F
|
||||
#define DA732X_REG_ID 0x81
|
||||
#define DA732X_REG_ADC1_PD 0x90
|
||||
#define DA732X_REG_ADC1_HPF 0x93
|
||||
#define DA732X_REG_ADC1_SEL 0x94
|
||||
#define DA732X_REG_ADC1_EQ12 0x95
|
||||
#define DA732X_REG_ADC1_EQ34 0x96
|
||||
#define DA732X_REG_ADC1_EQ5 0x97
|
||||
#define DA732X_REG_ADC2_PD 0x98
|
||||
#define DA732X_REG_ADC2_HPF 0x9B
|
||||
#define DA732X_REG_ADC2_SEL 0x9C
|
||||
#define DA732X_REG_ADC2_EQ12 0x9D
|
||||
#define DA732X_REG_ADC2_EQ34 0x9E
|
||||
#define DA732X_REG_ADC2_EQ5 0x9F
|
||||
#define DA732X_REG_DAC1_HPF 0xA0
|
||||
#define DA732X_REG_DAC1_L_VOL 0xA1
|
||||
#define DA732X_REG_DAC1_R_VOL 0xA2
|
||||
#define DA732X_REG_DAC1_SEL 0xA3
|
||||
#define DA732X_REG_DAC1_SOFTMUTE 0xA4
|
||||
#define DA732X_REG_DAC1_EQ12 0xA5
|
||||
#define DA732X_REG_DAC1_EQ34 0xA6
|
||||
#define DA732X_REG_DAC1_EQ5 0xA7
|
||||
#define DA732X_REG_DAC2_HPF 0xB0
|
||||
#define DA732X_REG_DAC2_L_VOL 0xB1
|
||||
#define DA732X_REG_DAC2_R_VOL 0xB2
|
||||
#define DA732X_REG_DAC2_SEL 0xB3
|
||||
#define DA732X_REG_DAC2_SOFTMUTE 0xB4
|
||||
#define DA732X_REG_DAC2_EQ12 0xB5
|
||||
#define DA732X_REG_DAC2_EQ34 0xB6
|
||||
#define DA732X_REG_DAC2_EQ5 0xB7
|
||||
#define DA732X_REG_DAC3_HPF 0xC0
|
||||
#define DA732X_REG_DAC3_VOL 0xC1
|
||||
#define DA732X_REG_DAC3_SEL 0xC3
|
||||
#define DA732X_REG_DAC3_SOFTMUTE 0xC4
|
||||
#define DA732X_REG_DAC3_EQ12 0xC5
|
||||
#define DA732X_REG_DAC3_EQ34 0xC6
|
||||
#define DA732X_REG_DAC3_EQ5 0xC7
|
||||
#define DA732X_REG_BIQ_BYP 0xD2
|
||||
#define DA732X_REG_DMA_CMD 0xD3
|
||||
#define DA732X_REG_DMA_ADDR0 0xD4
|
||||
#define DA732X_REG_DMA_ADDR1 0xD5
|
||||
#define DA732X_REG_DMA_DATA0 0xD6
|
||||
#define DA732X_REG_DMA_DATA1 0xD7
|
||||
#define DA732X_REG_DMA_DATA2 0xD8
|
||||
#define DA732X_REG_DMA_DATA3 0xD9
|
||||
#define DA732X_REG_DMA_STATUS 0xDA
|
||||
#define DA732X_REG_BROWNOUT 0xDF
|
||||
#define DA732X_REG_UNLOCK 0xE0
|
||||
|
||||
#define DA732X_MAX_REG DA732X_REG_UNLOCK
|
||||
/*
|
||||
* Bits
|
||||
*/
|
||||
|
||||
/* DA732X_REG_STATUS_EXT (addr=0x00) */
|
||||
#define DA732X_STATUS_EXT_DSP (1 << 4)
|
||||
#define DA732X_STATUS_EXT_CLEAR (0 << 0)
|
||||
|
||||
/* DA732X_REG_STATUS (addr=0x01) */
|
||||
#define DA732X_STATUS_PLL_LOCK (1 << 0)
|
||||
#define DA732X_STATUS_PLL_MCLK_DET (1 << 1)
|
||||
#define DA732X_STATUS_HPDET_OUT (1 << 2)
|
||||
#define DA732X_STATUS_INP_MIXDET_1 (1 << 3)
|
||||
#define DA732X_STATUS_INP_MIXDET_2 (1 << 4)
|
||||
#define DA732X_STATUS_BO_STATUS (1 << 5)
|
||||
|
||||
/* DA732X_REG_REF1 (addr=0x02) */
|
||||
#define DA732X_VMID_FASTCHG (1 << 1)
|
||||
#define DA732X_VMID_FASTDISCHG (1 << 2)
|
||||
#define DA732X_REFBUFX2_EN (1 << 6)
|
||||
#define DA732X_REFBUFX2_DIS (0 << 6)
|
||||
|
||||
/* DA732X_REG_BIAS_EN (addr=0x03) */
|
||||
#define DA732X_BIAS_BOOST_MASK (3 << 0)
|
||||
#define DA732X_BIAS_BOOST_100PC (0 << 0)
|
||||
#define DA732X_BIAS_BOOST_133PC (1 << 0)
|
||||
#define DA732X_BIAS_BOOST_88PC (2 << 0)
|
||||
#define DA732X_BIAS_BOOST_50PC (3 << 0)
|
||||
#define DA732X_BIAS_EN (1 << 7)
|
||||
#define DA732X_BIAS_DIS (0 << 7)
|
||||
|
||||
/* DA732X_REG_BIAS1 (addr=0x04) */
|
||||
#define DA732X_BIAS1_HP_DAC_BIAS_MASK (3 << 0)
|
||||
#define DA732X_BIAS1_HP_DAC_BIAS_100PC (0 << 0)
|
||||
#define DA732X_BIAS1_HP_DAC_BIAS_150PC (1 << 0)
|
||||
#define DA732X_BIAS1_HP_DAC_BIAS_50PC (2 << 0)
|
||||
#define DA732X_BIAS1_HP_DAC_BIAS_75PC (3 << 0)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_MASK (7 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_100PC (0 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_125PC (1 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_150PC (2 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_175PC (3 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_200PC (4 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_250PC (5 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_300PC (6 << 4)
|
||||
#define DA732X_BIAS1_HP_OUT_BIAS_350PC (7 << 4)
|
||||
|
||||
/* DA732X_REG_BIAS2 (addr=0x05) */
|
||||
#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK (3 << 0)
|
||||
#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC (0 << 0)
|
||||
#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC (1 << 0)
|
||||
#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC (2 << 0)
|
||||
#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC (3 << 0)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK (7 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC (0 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC (1 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC (2 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC (3 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC (4 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC (5 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC (6 << 4)
|
||||
#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC (7 << 4)
|
||||
|
||||
/* DA732X_REG_BIAS3 (addr=0x06) */
|
||||
#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK (3 << 0)
|
||||
#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC (0 << 0)
|
||||
#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC (1 << 0)
|
||||
#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC (2 << 0)
|
||||
#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC (3 << 0)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK (7 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC (0 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC (1 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC (2 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC (3 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC (4 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC (5 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC (6 << 4)
|
||||
#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC (7 << 4)
|
||||
|
||||
/* DA732X_REG_BIAS4 (addr=0x07) */
|
||||
#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK (3 << 0)
|
||||
#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC (0 << 0)
|
||||
#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC (1 << 0)
|
||||
#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC (2 << 0)
|
||||
#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC (3 << 0)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK (7 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC (0 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC (1 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC (2 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC (3 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC (4 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC (5 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC (6 << 4)
|
||||
#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC (7 << 4)
|
||||
|
||||
/* DA732X_REG_SIF_VDD_SEL (addr=0x08) */
|
||||
#define DA732X_SIF_VDD_SEL_AIFA_VDD2 (1 << 0)
|
||||
#define DA732X_SIF_VDD_SEL_AIFB_VDD2 (1 << 1)
|
||||
#define DA732X_SIF_VDD_SEL_CIFA_VDD2 (1 << 4)
|
||||
|
||||
/* DA732X_REG_MICBIAS2/1 (addr=0x0F/0x10) */
|
||||
#define DA732X_MICBIAS_VOLTAGE_MASK (0x0F << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V (0x00 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V05 (0x01 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V1 (0x02 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V15 (0x03 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V2 (0x04 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V25 (0x05 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V3 (0x06 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V35 (0x07 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V4 (0x08 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V45 (0x09 << 0)
|
||||
#define DA732X_MICBIAS_VOLTAGE_2V5 (0x0A << 0)
|
||||
#define DA732X_MICBIAS_EN (1 << 7)
|
||||
#define DA732X_MICBIAS_EN_SHIFT 7
|
||||
#define DA732X_MICBIAS_VOLTAGE_SHIFT 0
|
||||
#define DA732X_MICBIAS_VOLTAGE_MAX 0x0B
|
||||
|
||||
/* DA732X_REG_MICDET (addr=0x11) */
|
||||
#define DA732X_MICDET_INP_MICRES (1 << 0)
|
||||
#define DA732X_MICDET_INP_MICHOOK (1 << 1)
|
||||
#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS (0 << 0)
|
||||
#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS (1 << 0)
|
||||
#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS (2 << 0)
|
||||
#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS (3 << 0)
|
||||
#define DA732X_MICDET_INP_MICDET_EN (1 << 7)
|
||||
|
||||
/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */
|
||||
#define DA732X_MICBOOST_MASK 0x7
|
||||
#define DA732X_MICBOOST_SHIFT 0
|
||||
#define DA732X_MICBOOST_MIN 0x1
|
||||
#define DA732X_MICBOOST_MAX DA732X_MICBOOST_MASK
|
||||
|
||||
/* DA732X_REG_MIC1/2/3 (addr=0x13/0x15/0x19) */
|
||||
#define DA732X_MIC_VOL_SHIFT 0
|
||||
#define DA732X_MIC_VOL_VAL_MASK 0x1F
|
||||
#define DA732X_MIC_MUTE_SHIFT 6
|
||||
#define DA732X_MIC_EN_SHIFT 7
|
||||
#define DA732X_MIC_VOL_VAL_MIN 0x7
|
||||
#define DA732X_MIC_VOL_VAL_MAX DA732X_MIC_VOL_VAL_MASK
|
||||
|
||||
/* DA732X_REG_AUX1L/R (addr=0x16/0x17) */
|
||||
#define DA732X_AUX_VOL_SHIFT 0
|
||||
#define DA732X_AUX_VOL_MASK 0x7
|
||||
#define DA732X_AUX_MUTE_SHIFT 6
|
||||
#define DA732X_AUX_EN_SHIFT 7
|
||||
#define DA732X_AUX_VOL_VAL_MAX DA732X_AUX_VOL_MASK
|
||||
|
||||
/* DA732X_REG_INP_PINBIAS (addr=0x1A) */
|
||||
#define DA732X_INP_MICL_PINBIAS_EN (1 << 0)
|
||||
#define DA732X_INP_MICR_PINBIAS_EN (1 << 1)
|
||||
#define DA732X_INP_AUX1L_PINBIAS_EN (1 << 2)
|
||||
#define DA732X_INP_AUX1R_PINBIAS_EN (1 << 3)
|
||||
#define DA732X_INP_AUX2_PINBIAS_EN (1 << 4)
|
||||
|
||||
/* DA732X_REG_INP_ZC_EN (addr=0x1B) */
|
||||
#define DA732X_MIC1_PRE_ZC_EN (1 << 0)
|
||||
#define DA732X_MIC1_ZC_EN (1 << 1)
|
||||
#define DA732X_MIC2_PRE_ZC_EN (1 << 2)
|
||||
#define DA732X_MIC2_ZC_EN (1 << 3)
|
||||
#define DA732X_AUXL_ZC_EN (1 << 4)
|
||||
#define DA732X_AUXR_ZC_EN (1 << 5)
|
||||
#define DA732X_MIC3_PRE_ZC_EN (1 << 6)
|
||||
#define DA732X_MIC3_ZC_EN (1 << 7)
|
||||
|
||||
/* DA732X_REG_INP_MUX (addr=0x1D) */
|
||||
#define DA732X_INP_ADC1L_MUX_SEL_AUX1L (0 << 0)
|
||||
#define DA732X_INP_ADC1L_MUX_SEL_MIC1 (1 << 0)
|
||||
#define DA732X_INP_ADC1R_MUX_SEL_MASK (3 << 2)
|
||||
#define DA732X_INP_ADC1R_MUX_SEL_AUX1R (0 << 2)
|
||||
#define DA732X_INP_ADC1R_MUX_SEL_MIC2 (1 << 2)
|
||||
#define DA732X_INP_ADC1R_MUX_SEL_MIC3 (2 << 2)
|
||||
#define DA732X_INP_ADC2L_MUX_SEL_AUX1L (0 << 4)
|
||||
#define DA732X_INP_ADC2L_MUX_SEL_MICL (1 << 4)
|
||||
#define DA732X_INP_ADC2R_MUX_SEL_MASK (3 << 6)
|
||||
#define DA732X_INP_ADC2R_MUX_SEL_AUX1R (0 << 6)
|
||||
#define DA732X_INP_ADC2R_MUX_SEL_MICR (1 << 6)
|
||||
#define DA732X_INP_ADC2R_MUX_SEL_AUX2 (2 << 6)
|
||||
#define DA732X_ADC1L_MUX_SEL_SHIFT 0
|
||||
#define DA732X_ADC1R_MUX_SEL_SHIFT 2
|
||||
#define DA732X_ADC2L_MUX_SEL_SHIFT 4
|
||||
#define DA732X_ADC2R_MUX_SEL_SHIFT 6
|
||||
|
||||
/* DA732X_REG_HP_DET (addr=0x20) */
|
||||
#define DA732X_HP_DET_AZ (1 << 0)
|
||||
#define DA732X_HP_DET_SEL1 (1 << 1)
|
||||
#define DA732X_HP_DET_IS_MASK (3 << 2)
|
||||
#define DA732X_HP_DET_IS_0_5UA (0 << 2)
|
||||
#define DA732X_HP_DET_IS_1UA (1 << 2)
|
||||
#define DA732X_HP_DET_IS_2UA (2 << 2)
|
||||
#define DA732X_HP_DET_IS_4UA (3 << 2)
|
||||
#define DA732X_HP_DET_RS_MASK (3 << 4)
|
||||
#define DA732X_HP_DET_RS_INFINITE (0 << 4)
|
||||
#define DA732X_HP_DET_RS_100KOHM (1 << 4)
|
||||
#define DA732X_HP_DET_RS_10KOHM (2 << 4)
|
||||
#define DA732X_HP_DET_RS_1KOHM (3 << 4)
|
||||
#define DA732X_HP_DET_EN (1 << 7)
|
||||
|
||||
/* DA732X_REG_HPL_DAC_OFFSET (addr=0x21/0x26) */
|
||||
#define DA732X_HP_DAC_OFFSET_TRIM_MASK (0x3F << 0)
|
||||
#define DA732X_HP_DAC_OFFSET_DAC_SIGN (1 << 6)
|
||||
|
||||
/* DA732X_REG_HPL_DAC_OFF_CNTL (addr=0x22/0x27) */
|
||||
#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK (7 << 0)
|
||||
#define DA732X_HP_DAC_OFF_CNTL_COMPO (1 << 3)
|
||||
#define DA732X_HP_DAC_OFF_CALIBRATION (1 << 0)
|
||||
#define DA732X_HP_DAC_OFF_SCALE_STEPS (1 << 1)
|
||||
#define DA732X_HP_DAC_OFF_MASK 0x7F
|
||||
#define DA732X_HP_DAC_COMPO_SHIFT 3
|
||||
|
||||
/* DA732X_REG_HPL_OUT_OFFSET (addr=0x23/0x28) */
|
||||
#define DA732X_HP_OUT_OFFSET_MASK (0xFF << 0)
|
||||
#define DA732X_HP_DAC_OFFSET_TRIM_VAL 0x7F
|
||||
|
||||
/* DA732X_REG_HPL/R (addr=0x24/0x29) */
|
||||
#define DA732X_HP_OUT_SIGN (1 << 0)
|
||||
#define DA732X_HP_OUT_COMP (1 << 1)
|
||||
#define DA732X_HP_OUT_RESERVED (1 << 2)
|
||||
#define DA732X_HP_OUT_COMPO (1 << 3)
|
||||
#define DA732X_HP_OUT_DAC_EN (1 << 4)
|
||||
#define DA732X_HP_OUT_HIZ_EN (1 << 5)
|
||||
#define DA732X_HP_OUT_HIZ_DIS (0 << 5)
|
||||
#define DA732X_HP_OUT_MUTE (1 << 6)
|
||||
#define DA732X_HP_OUT_EN (1 << 7)
|
||||
#define DA732X_HP_OUT_COMPO_SHIFT 3
|
||||
#define DA732X_HP_OUT_DAC_EN_SHIFT 4
|
||||
#define DA732X_HP_HIZ_SHIFT 5
|
||||
#define DA732X_HP_MUTE_SHIFT 6
|
||||
#define DA732X_HP_OUT_EN_SHIFT 7
|
||||
|
||||
#define DA732X_OUT_HIZ_EN (1 << 5)
|
||||
#define DA732X_OUT_HIZ_DIS (0 << 5)
|
||||
|
||||
/* DA732X_REG_HPL/R_VOL (addr=0x25/0x2A) */
|
||||
#define DA732X_HP_VOL_VAL_MASK 0xF
|
||||
#define DA732X_HP_VOL_SHIFT 0
|
||||
#define DA732X_HP_VOL_VAL_MAX DA732X_HP_VOL_VAL_MASK
|
||||
|
||||
/* DA732X_REG_LIN2/3/4 (addr=0x2B/0x2C/0x2D) */
|
||||
#define DA732X_LOUT_VOL_SHIFT 0
|
||||
#define DA732X_LOUT_VOL_MASK 0x0F
|
||||
#define DA732X_LOUT_DAC_OFF (0 << 4)
|
||||
#define DA732X_LOUT_DAC_EN (1 << 4)
|
||||
#define DA732X_LOUT_HIZ_N_DIS (0 << 5)
|
||||
#define DA732X_LOUT_HIZ_N_EN (1 << 5)
|
||||
#define DA732X_LOUT_UNMUTED (0 << 6)
|
||||
#define DA732X_LOUT_MUTED (1 << 6)
|
||||
#define DA732X_LOUT_EN (0 << 7)
|
||||
#define DA732X_LOUT_DIS (1 << 7)
|
||||
#define DA732X_LOUT_DAC_EN_SHIFT 4
|
||||
#define DA732X_LOUT_MUTE_SHIFT 6
|
||||
#define DA732X_LIN_OUT_EN_SHIFT 7
|
||||
#define DA732X_LOUT_VOL_VAL_MAX DA732X_LOUT_VOL_MASK
|
||||
|
||||
/* DA732X_REG_OUT_ZC_EN (addr=0x2E) */
|
||||
#define DA732X_HPL_ZC_EN_SHIFT 0
|
||||
#define DA732X_HPR_ZC_EN_SHIFT 1
|
||||
#define DA732X_HPL_ZC_EN (1 << 0)
|
||||
#define DA732X_HPL_ZC_DIS (0 << 0)
|
||||
#define DA732X_HPR_ZC_EN (1 << 1)
|
||||
#define DA732X_HPR_ZC_DIS (0 << 1)
|
||||
#define DA732X_LIN2_ZC_EN (1 << 2)
|
||||
#define DA732X_LIN2_ZC_DIS (0 << 2)
|
||||
#define DA732X_LIN3_ZC_EN (1 << 3)
|
||||
#define DA732X_LIN3_ZC_DIS (0 << 3)
|
||||
#define DA732X_LIN4_ZC_EN (1 << 4)
|
||||
#define DA732X_LIN4_ZC_DIS (0 << 4)
|
||||
|
||||
/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */
|
||||
#define DA732X_HP_OUT_GNDSEL (1 << 0)
|
||||
|
||||
/* DA732X_REG_CP_HP2 (addr=0x3a) */
|
||||
#define DA732X_HP_CP_PULSESKIP (1 << 0)
|
||||
#define DA732X_HP_CP_REG (1 << 1)
|
||||
#define DA732X_HP_CP_EN (1 << 3)
|
||||
#define DA732X_HP_CP_DIS (0 << 3)
|
||||
|
||||
/* DA732X_REG_CP_CTRL1 (addr=0x40) */
|
||||
#define DA732X_CP_MODE_MASK (7 << 1)
|
||||
#define DA732X_CP_CTRL_STANDBY (0 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD6 (2 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD5 (3 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD4 (4 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD3 (5 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD2 (6 << 1)
|
||||
#define DA732X_CP_CTRL_CPVDD1 (7 << 1)
|
||||
#define DA723X_CP_DIS (0 << 7)
|
||||
#define DA732X_CP_EN (1 << 7)
|
||||
|
||||
/* DA732X_REG_CP_CTRL2 (addr=0x41) */
|
||||
#define DA732X_CP_BOOST (1 << 0)
|
||||
#define DA732X_CP_MANAGE_MAGNITUDE (2 << 2)
|
||||
|
||||
/* DA732X_REG_CP_CTRL3 (addr=0x42) */
|
||||
#define DA732X_CP_1MHZ (0 << 0)
|
||||
#define DA732X_CP_500KHZ (1 << 0)
|
||||
#define DA732X_CP_250KHZ (2 << 0)
|
||||
#define DA732X_CP_125KHZ (3 << 0)
|
||||
#define DA732X_CP_63KHZ (4 << 0)
|
||||
#define DA732X_CP_0KHZ (5 << 0)
|
||||
|
||||
/* DA732X_REG_PLL_CTRL (addr=0x53) */
|
||||
#define DA732X_PLL_INDIV_MASK (3 << 0)
|
||||
#define DA732X_PLL_SRM_EN (1 << 2)
|
||||
#define DA732X_PLL_EN (1 << 7)
|
||||
#define DA732X_PLL_BYPASS (0 << 0)
|
||||
|
||||
/* DA732X_REG_CLK_CTRL (addr=0x54) */
|
||||
#define DA732X_SR1_MASK (0xF)
|
||||
#define DA732X_SR2_MASK (0xF0)
|
||||
|
||||
/* DA732X_REG_CLK_DSP (addr=0x5A) */
|
||||
#define DA732X_DSP_FREQ_MASK (7 << 0)
|
||||
#define DA732X_DSP_FREQ_12MHZ (0 << 0)
|
||||
#define DA732X_DSP_FREQ_24MHZ (1 << 0)
|
||||
#define DA732X_DSP_FREQ_36MHZ (2 << 0)
|
||||
#define DA732X_DSP_FREQ_48MHZ (3 << 0)
|
||||
#define DA732X_DSP_FREQ_60MHZ (4 << 0)
|
||||
#define DA732X_DSP_FREQ_72MHZ (5 << 0)
|
||||
#define DA732X_DSP_FREQ_84MHZ (6 << 0)
|
||||
#define DA732X_DSP_FREQ_96MHZ (7 << 0)
|
||||
|
||||
/* DA732X_REG_CLK_EN1 (addr=0x5B) */
|
||||
#define DA732X_DSP_CLK_EN (1 << 0)
|
||||
#define DA732X_SYS3_CLK_EN (1 << 1)
|
||||
#define DA732X_DSP12_CLK_EN (1 << 2)
|
||||
#define DA732X_PC_CLK_EN (1 << 3)
|
||||
#define DA732X_MCLK_SQR_EN (1 << 7)
|
||||
|
||||
/* DA732X_REG_CLK_EN2 (addr=0x5C) */
|
||||
#define DA732X_UART_CLK_EN (1 << 1)
|
||||
#define DA732X_CP_CLK_EN (1 << 2)
|
||||
#define DA732X_CP_CLK_DIS (0 << 2)
|
||||
|
||||
/* DA732X_REG_CLK_EN3 (addr=0x5D) */
|
||||
#define DA732X_ADCA_BB_CLK_EN (1 << 0)
|
||||
#define DA732X_ADCC_BB_CLK_EN (1 << 4)
|
||||
|
||||
/* DA732X_REG_CLK_EN4 (addr=0x5E) */
|
||||
#define DA732X_DACA_BB_CLK_EN (1 << 0)
|
||||
#define DA732X_DACC_BB_CLK_EN (1 << 4)
|
||||
#define DA732X_DACA_BB_CLK_SHIFT 0
|
||||
#define DA732X_DACC_BB_CLK_SHIFT 4
|
||||
|
||||
/* DA732X_REG_CLK_EN5 (addr=0x5F) */
|
||||
#define DA732X_DACE_BB_CLK_EN (1 << 0)
|
||||
#define DA732X_DACE_BB_CLK_SHIFT 0
|
||||
|
||||
/* DA732X_REG_AIF_MCLK (addr=0x60) */
|
||||
#define DA732X_AIFM_FRAME_64 (1 << 2)
|
||||
#define DA732X_AIFM_SRC_SEL_AIFA (1 << 6)
|
||||
#define DA732X_CLK_GENERATION_AIF_A (1 << 4)
|
||||
#define DA732X_NO_CLK_GENERATION 0x0
|
||||
|
||||
/* DA732X_REG_AIFA1 (addr=0x61) */
|
||||
#define DA732X_AIF_WORD_MASK (0x3 << 0)
|
||||
#define DA732X_AIF_WORD_16 (0 << 0)
|
||||
#define DA732X_AIF_WORD_20 (1 << 0)
|
||||
#define DA732X_AIF_WORD_24 (2 << 0)
|
||||
#define DA732X_AIF_WORD_32 (3 << 0)
|
||||
#define DA732X_AIF_TDM_MONO_SHIFT (1 << 6)
|
||||
#define DA732X_AIF1_CLK_MASK (1 << 7)
|
||||
#define DA732X_AIF_SLAVE (0 << 7)
|
||||
#define DA732X_AIF_CLK_FROM_SRC (1 << 7)
|
||||
|
||||
/* DA732X_REG_AIFA3 (addr=0x63) */
|
||||
#define DA732X_AIF_MODE_SHIFT 0
|
||||
#define DA732X_AIF_MODE_MASK 0x3
|
||||
#define DA732X_AIF_I2S_MODE (0 << 0)
|
||||
#define DA732X_AIF_LEFT_J_MODE (1 << 0)
|
||||
#define DA732X_AIF_RIGHT_J_MODE (2 << 0)
|
||||
#define DA732X_AIF_DSP_MODE (3 << 0)
|
||||
#define DA732X_AIF_WCLK_INV (1 << 4)
|
||||
#define DA732X_AIF_BCLK_INV (1 << 5)
|
||||
#define DA732X_AIF_EN (1 << 7)
|
||||
#define DA732X_AIF_EN_SHIFT 7
|
||||
|
||||
/* DA732X_REG_PC_CTRL (addr=0x6a) */
|
||||
#define DA732X_PC_PULSE_AIFA (0 << 0)
|
||||
#define DA732X_PC_PULSE_AIFB (1 << 0)
|
||||
#define DA732X_PC_RESYNC_AUT (1 << 6)
|
||||
#define DA732X_PC_RESYNC_NOT_AUT (0 << 6)
|
||||
#define DA732X_PC_SAME (1 << 7)
|
||||
|
||||
/* DA732X_REG_DATA_ROUTE (addr=0x70) */
|
||||
#define DA732X_ADC1_TO_AIFA (0 << 0)
|
||||
#define DA732X_DSP_TO_AIFA (1 << 0)
|
||||
#define DA732X_ADC2_TO_AIFB (0 << 1)
|
||||
#define DA732X_DSP_TO_AIFB (1 << 1)
|
||||
#define DA732X_AIFA_TO_DAC1L (0 << 2)
|
||||
#define DA732X_DSP_TO_DAC1L (1 << 2)
|
||||
#define DA732X_AIFA_TO_DAC1R (0 << 3)
|
||||
#define DA732X_DSP_TO_DAC1R (1 << 3)
|
||||
#define DA732X_AIFB_TO_DAC2L (0 << 4)
|
||||
#define DA732X_DSP_TO_DAC2L (1 << 4)
|
||||
#define DA732X_AIFB_TO_DAC2R (0 << 5)
|
||||
#define DA732X_DSP_TO_DAC2R (1 << 5)
|
||||
#define DA732X_AIFB_TO_DAC3 (0 << 6)
|
||||
#define DA732X_DSP_TO_DAC3 (1 << 6)
|
||||
#define DA732X_BYPASS_DSP (0 << 0)
|
||||
#define DA732X_ALL_TO_DSP (0x7F << 0)
|
||||
|
||||
/* DA732X_REG_DSP_CTRL (addr=0x71) */
|
||||
#define DA732X_DIGITAL_EN (1 << 0)
|
||||
#define DA732X_DIGITAL_RESET (0 << 0)
|
||||
#define DA732X_DSP_CORE_EN (1 << 1)
|
||||
#define DA732X_DSP_CORE_RESET (0 << 1)
|
||||
|
||||
/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/
|
||||
#define DA732X_HP_DRIVER_EN (1 << 0)
|
||||
#define DA732X_HP_GATE_LOW (1 << 2)
|
||||
#define DA732X_HP_LOOP_GAIN_CTRL (1 << 3)
|
||||
|
||||
/* DA732X_REG_ID (addr=0x81)*/
|
||||
#define DA732X_ID_MINOR_MASK (0xF << 0)
|
||||
#define DA732X_ID_MAJOR_MASK (0xF << 4)
|
||||
|
||||
/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */
|
||||
#define DA732X_ADC_RST_MASK (0x3 << 0)
|
||||
#define DA732X_ADC_PD_MASK (0x3 << 2)
|
||||
#define DA732X_ADC_SET_ACT (0x3 << 0)
|
||||
#define DA732X_ADC_SET_RST (0x0 << 0)
|
||||
#define DA732X_ADC_ON (0x3 << 2)
|
||||
#define DA732X_ADC_OFF (0x0 << 2)
|
||||
|
||||
/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */
|
||||
#define DA732X_ADC_VOL_VAL_MASK 0x7
|
||||
#define DA732X_ADCL_VOL_SHIFT 0
|
||||
#define DA732X_ADCR_VOL_SHIFT 4
|
||||
#define DA732X_ADCL_EN_SHIFT 2
|
||||
#define DA732X_ADCR_EN_SHIFT 3
|
||||
#define DA732X_ADCL_EN (1 << 2)
|
||||
#define DA732X_ADCR_EN (1 << 3)
|
||||
#define DA732X_ADC_VOL_VAL_MAX DA732X_ADC_VOL_VAL_MASK
|
||||
|
||||
/*
|
||||
* DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b)
|
||||
* DA732x_REG_DAC1/2/3_HPG (addr=0xA5/0xB5/0xC5)
|
||||
*/
|
||||
#define DA732X_HPF_MUSIC_EN (1 << 3)
|
||||
#define DA732X_HPF_VOICE_EN ((1 << 3) | (1 << 7))
|
||||
#define DA732X_HPF_MASK ((1 << 3) | (1 << 7))
|
||||
#define DA732X_HPF_DIS ((0 << 3) | (0 << 7))
|
||||
|
||||
/* DA732X_REG_DAC1/2/3_VOL */
|
||||
#define DA732X_DAC_VOL_VAL_MASK 0x7F
|
||||
#define DA732X_DAC_VOL_SHIFT 0
|
||||
#define DA732X_DAC_VOL_VAL_MAX DA732X_DAC_VOL_VAL_MASK
|
||||
|
||||
/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */
|
||||
#define DA732X_DACL_EN_SHIFT 3
|
||||
#define DA732X_DACR_EN_SHIFT 7
|
||||
#define DA732X_DACL_MUTE_SHIFT 2
|
||||
#define DA732X_DACR_MUTE_SHIFT 6
|
||||
#define DA732X_DACL_EN (1 << 3)
|
||||
#define DA732X_DACR_EN (1 << 7)
|
||||
#define DA732X_DACL_SDM (1 << 0)
|
||||
#define DA732X_DACR_SDM (1 << 4)
|
||||
#define DA732X_DACL_MUTE (1 << 2)
|
||||
#define DA732X_DACR_MUTE (1 << 6)
|
||||
|
||||
/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */
|
||||
#define DA732X_SOFTMUTE_EN (1 << 7)
|
||||
#define DA732X_GAIN_RAMPED (1 << 6)
|
||||
#define DA732X_16_SAMPLES (4 << 0)
|
||||
#define DA732X_SOFTMUTE_MASK (1 << 7)
|
||||
#define DA732X_SOFTMUTE_SHIFT 7
|
||||
|
||||
/*
|
||||
* DA732x_REG_ADC1/2_EQ12 (addr=0x95/0x9D)
|
||||
* DA732x_REG_ADC1/2_EQ34 (addr=0x96/0x9E)
|
||||
* DA732x_REG_ADC1/2_EQ5 (addr=0x97/0x9F)
|
||||
* DA732x_REG_DAC1/2/3_EQ12 (addr=0xA5/0xB5/0xC5)
|
||||
* DA732x_REG_DAC1/2/3_EQ34 (addr=0xA6/0xB6/0xC6)
|
||||
* DA732x_REG_DAC1/2/3_EQ5 (addr=0xA7/0xB7/0xB7)
|
||||
*/
|
||||
#define DA732X_EQ_VOL_VAL_MASK 0xF
|
||||
#define DA732X_EQ_BAND1_SHIFT 0
|
||||
#define DA732X_EQ_BAND2_SHIFT 4
|
||||
#define DA732X_EQ_BAND3_SHIFT 0
|
||||
#define DA732X_EQ_BAND4_SHIFT 4
|
||||
#define DA732X_EQ_BAND5_SHIFT 0
|
||||
#define DA732X_EQ_OVERALL_SHIFT 4
|
||||
#define DA732X_EQ_OVERALL_VOL_VAL_MASK 0x3
|
||||
#define DA732X_EQ_DIS (0 << 7)
|
||||
#define DA732X_EQ_EN (1 << 7)
|
||||
#define DA732X_EQ_EN_SHIFT 7
|
||||
#define DA732X_EQ_VOL_VAL_MAX DA732X_EQ_VOL_VAL_MASK
|
||||
#define DA732X_EQ_OVERALL_VOL_VAL_MAX DA732X_EQ_OVERALL_VOL_VAL_MASK
|
||||
|
||||
/* DA732X_REG_DMA_CMD (addr=0xD3) */
|
||||
#define DA732X_SEL_DSP_DMA_MASK (3 << 0)
|
||||
#define DA732X_SEL_DSP_DMA_DIS (0 << 0)
|
||||
#define DA732X_SEL_DSP_DMA_PMEM (1 << 0)
|
||||
#define DA732X_SEL_DSP_DMA_XMEM (2 << 0)
|
||||
#define DA732X_SEL_DSP_DMA_YMEM (3 << 0)
|
||||
#define DA732X_DSP_RW_MASK (1 << 4)
|
||||
#define DA732X_DSP_DMA_WRITE (0 << 4)
|
||||
#define DA732X_DSP_DMA_READ (1 << 4)
|
||||
|
||||
/* DA732X_REG_DMA_STATUS (addr=0xDA) */
|
||||
#define DA732X_DSP_DMA_FREE (0 << 0)
|
||||
#define DA732X_DSP_DMA_BUSY (1 << 0)
|
||||
|
||||
#endif /* __DA732X_REG_H_ */
|
||||
1554
sound/soc/codecs/da9055.c
Normal file
1554
sound/soc/codecs/da9055.c
Normal file
File diff suppressed because it is too large
Load diff
87
sound/soc/codecs/dmic.c
Normal file
87
sound/soc/codecs/dmic.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* dmic.c -- SoC audio for Generic Digital MICs
|
||||
*
|
||||
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
static struct snd_soc_dai_driver dmic_dai = {
|
||||
.name = "dmic-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE
|
||||
| SNDRV_PCM_FMTBIT_S24_LE
|
||||
| SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_INPUT("DMic"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"DMIC AIF", NULL, "DMic"},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_dmic = {
|
||||
.dapm_widgets = dmic_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
|
||||
.dapm_routes = intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(intercon),
|
||||
};
|
||||
|
||||
static int dmic_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_dmic, &dmic_dai, 1);
|
||||
}
|
||||
|
||||
static int dmic_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:dmic-codec");
|
||||
|
||||
static struct platform_driver dmic_driver = {
|
||||
.driver = {
|
||||
.name = "dmic-codec",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = dmic_dev_probe,
|
||||
.remove = dmic_dev_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(dmic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Generic DMIC driver");
|
||||
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
133
sound/soc/codecs/dummy_codec.c
Normal file
133
sound/soc/codecs/dummy_codec.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* ALSA SoC dummy codec driver
|
||||
*
|
||||
* This driver provides two dummy dais.
|
||||
*
|
||||
* Copyright (c) 2013 Samsung Electronics
|
||||
* http://www.samsungsemi.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#define DRV_NAME "dummy-codec"
|
||||
|
||||
#define RATES SNDRV_PCM_RATE_8000_192000
|
||||
#define FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dummy;
|
||||
|
||||
static struct snd_soc_dai_driver dummy_codec_dai[] = {
|
||||
{
|
||||
.name = "dummy-aif1",
|
||||
.playback = {
|
||||
.stream_name = "AIF1 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF1 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
}, {
|
||||
.name = "dummy-aif2",
|
||||
.playback = {
|
||||
.stream_name = "AIF2 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF2 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
}, {
|
||||
.name = "dummy-aif3",
|
||||
.playback = {
|
||||
.stream_name = "AIF3 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF3 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
}, {
|
||||
.name = "dummy-aif4",
|
||||
.playback = {
|
||||
.stream_name = "AIF4 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF4 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 384,
|
||||
.rates = RATES,
|
||||
.formats = FORMATS,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static int dummy_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dummy,
|
||||
dummy_codec_dai, ARRAY_SIZE(dummy_codec_dai));
|
||||
}
|
||||
|
||||
static int dummy_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id dummy_codec_of_match[] = {
|
||||
{ .compatible = "samsung,dummy-codec", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dummy_codec_of_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct platform_driver dummy_codec_driver = {
|
||||
.probe = dummy_codec_probe,
|
||||
.remove = dummy_codec_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(dummy_codec_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dummy_codec_driver);
|
||||
|
||||
MODULE_AUTHOR("Yeongman Seo <yman.seo@samsung.com>");
|
||||
MODULE_DESCRIPTION("Dummy codec driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
60
sound/soc/codecs/es8328-i2c.c
Normal file
60
sound/soc/codecs/es8328-i2c.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver
|
||||
*
|
||||
* Copyright 2014 Sutajio Ko-Usagi PTE LTD
|
||||
*
|
||||
* Author: Sean Cross <xobs@kosagi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "es8328.h"
|
||||
|
||||
static const struct i2c_device_id es8328_id[] = {
|
||||
{ "es8328", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, es8328_id);
|
||||
|
||||
static const struct of_device_id es8328_of_match[] = {
|
||||
{ .compatible = "everest,es8328", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, es8328_of_match);
|
||||
|
||||
static int es8328_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return es8328_probe(&i2c->dev,
|
||||
devm_regmap_init_i2c(i2c, &es8328_regmap_config));
|
||||
}
|
||||
|
||||
static int es8328_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver es8328_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "es8328",
|
||||
.of_match_table = es8328_of_match,
|
||||
},
|
||||
.probe = es8328_i2c_probe,
|
||||
.remove = es8328_i2c_remove,
|
||||
.id_table = es8328_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(es8328_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
|
||||
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
49
sound/soc/codecs/es8328-spi.c
Normal file
49
sound/soc/codecs/es8328-spi.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* es8328.c -- ES8328 ALSA SoC SPI Audio driver
|
||||
*
|
||||
* Copyright 2014 Sutajio Ko-Usagi PTE LTD
|
||||
*
|
||||
* Author: Sean Cross <xobs@kosagi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
#include "es8328.h"
|
||||
|
||||
static const struct of_device_id es8328_of_match[] = {
|
||||
{ .compatible = "everest,es8328", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, es8328_of_match);
|
||||
|
||||
static int es8328_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return es8328_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &es8328_regmap_config));
|
||||
}
|
||||
|
||||
static int es8328_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver es8328_spi_driver = {
|
||||
.driver = {
|
||||
.name = "es8328",
|
||||
.of_match_table = es8328_of_match,
|
||||
},
|
||||
.probe = es8328_spi_probe,
|
||||
.remove = es8328_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(es8328_spi_driver);
|
||||
MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
|
||||
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
756
sound/soc/codecs/es8328.c
Normal file
756
sound/soc/codecs/es8328.c
Normal file
|
|
@ -0,0 +1,756 @@
|
|||
/*
|
||||
* es8328.c -- ES8328 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2014 Sutajio Ko-Usagi PTE LTD
|
||||
*
|
||||
* Author: Sean Cross <xobs@kosagi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "es8328.h"
|
||||
|
||||
#define ES8328_SYSCLK_RATE_1X 11289600
|
||||
#define ES8328_SYSCLK_RATE_2X 22579200
|
||||
|
||||
/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */
|
||||
static struct {
|
||||
int rate;
|
||||
u8 ratio;
|
||||
} mclk_ratios[] = {
|
||||
{ 8000, 9 },
|
||||
{11025, 7 },
|
||||
{22050, 4 },
|
||||
{44100, 2 },
|
||||
};
|
||||
|
||||
/* regulator supplies for sgtl5000, VDDD is an optional external supply */
|
||||
enum sgtl5000_regulator_supplies {
|
||||
DVDD,
|
||||
AVDD,
|
||||
PVDD,
|
||||
HPVDD,
|
||||
ES8328_SUPPLY_NUM
|
||||
};
|
||||
|
||||
/* vddd is optional supply */
|
||||
static const char * const supply_names[ES8328_SUPPLY_NUM] = {
|
||||
"DVDD",
|
||||
"AVDD",
|
||||
"PVDD",
|
||||
"HPVDD",
|
||||
};
|
||||
|
||||
#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
|
||||
SNDRV_PCM_RATE_22050 | \
|
||||
SNDRV_PCM_RATE_11025)
|
||||
#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
struct es8328_priv {
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
int playback_fs;
|
||||
bool deemph;
|
||||
struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
|
||||
};
|
||||
|
||||
/*
|
||||
* ES8328 Controls
|
||||
*/
|
||||
|
||||
static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert",
|
||||
"L + R Invert"};
|
||||
static SOC_ENUM_SINGLE_DECL(adcpol,
|
||||
ES8328_ADCCONTROL6, 6, adcpol_txt);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
|
||||
|
||||
static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
|
||||
|
||||
static int es8328_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
int val, i, best;
|
||||
|
||||
/*
|
||||
* If we're using deemphasis select the nearest available sample
|
||||
* rate.
|
||||
*/
|
||||
if (es8328->deemph) {
|
||||
best = 1;
|
||||
for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
|
||||
if (abs(deemph_settings[i] - es8328->playback_fs) <
|
||||
abs(deemph_settings[best] - es8328->playback_fs))
|
||||
best = i;
|
||||
}
|
||||
|
||||
val = best << 1;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "Set deemphasis %d\n", val);
|
||||
|
||||
return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
|
||||
}
|
||||
|
||||
static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = es8328->deemph;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
int deemph = ucontrol->value.integer.value[0];
|
||||
int ret;
|
||||
|
||||
if (deemph > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = es8328_set_deemph(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
es8328->deemph = deemph;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const struct snd_kcontrol_new es8328_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Capture Digital Volume",
|
||||
ES8328_ADCCONTROL8, ES8328_ADCCONTROL9,
|
||||
0, 0xc0, 1, dac_adc_tlv),
|
||||
SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
|
||||
es8328_get_deemph, es8328_put_deemph),
|
||||
|
||||
SOC_ENUM("Capture Polarity", adcpol),
|
||||
|
||||
SOC_SINGLE_TLV("Left Mixer Left Bypass Volume",
|
||||
ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv),
|
||||
SOC_SINGLE_TLV("Left Mixer Right Bypass Volume",
|
||||
ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv),
|
||||
SOC_SINGLE_TLV("Right Mixer Left Bypass Volume",
|
||||
ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv),
|
||||
SOC_SINGLE_TLV("Right Mixer Right Bypass Volume",
|
||||
ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("PCM Volume",
|
||||
ES8328_LDACVOL, ES8328_RDACVOL,
|
||||
0, ES8328_DACVOL_MAX, 1, dac_adc_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Output 1 Playback Volume",
|
||||
ES8328_LOUT1VOL, ES8328_ROUT1VOL,
|
||||
0, ES8328_OUT1VOL_MAX, 0, play_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Output 2 Playback Volume",
|
||||
ES8328_LOUT2VOL, ES8328_ROUT2VOL,
|
||||
0, ES8328_OUT2VOL_MAX, 0, play_tlv),
|
||||
|
||||
SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1,
|
||||
4, 0, 8, 0, mic_tlv),
|
||||
};
|
||||
|
||||
/*
|
||||
* DAPM Controls
|
||||
*/
|
||||
|
||||
static const char * const es8328_line_texts[] = {
|
||||
"Line 1", "Line 2", "PGA", "Differential"};
|
||||
|
||||
static const struct soc_enum es8328_lline_enum =
|
||||
SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3,
|
||||
ARRAY_SIZE(es8328_line_texts),
|
||||
es8328_line_texts);
|
||||
static const struct snd_kcontrol_new es8328_left_line_controls =
|
||||
SOC_DAPM_ENUM("Route", es8328_lline_enum);
|
||||
|
||||
static const struct soc_enum es8328_rline_enum =
|
||||
SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0,
|
||||
ARRAY_SIZE(es8328_line_texts),
|
||||
es8328_line_texts);
|
||||
static const struct snd_kcontrol_new es8328_right_line_controls =
|
||||
SOC_DAPM_ENUM("Route", es8328_lline_enum);
|
||||
|
||||
/* Left Mixer */
|
||||
static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
|
||||
SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
|
||||
SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
|
||||
};
|
||||
|
||||
/* Right Mixer */
|
||||
static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
|
||||
SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
|
||||
SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
|
||||
};
|
||||
|
||||
static const char * const es8328_pga_sel[] = {
|
||||
"Line 1", "Line 2", "Line 3", "Differential"};
|
||||
|
||||
/* Left PGA Mux */
|
||||
static const struct soc_enum es8328_lpga_enum =
|
||||
SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6,
|
||||
ARRAY_SIZE(es8328_pga_sel),
|
||||
es8328_pga_sel);
|
||||
static const struct snd_kcontrol_new es8328_left_pga_controls =
|
||||
SOC_DAPM_ENUM("Route", es8328_lpga_enum);
|
||||
|
||||
/* Right PGA Mux */
|
||||
static const struct soc_enum es8328_rpga_enum =
|
||||
SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4,
|
||||
ARRAY_SIZE(es8328_pga_sel),
|
||||
es8328_pga_sel);
|
||||
static const struct snd_kcontrol_new es8328_right_pga_controls =
|
||||
SOC_DAPM_ENUM("Route", es8328_rpga_enum);
|
||||
|
||||
/* Differential Mux */
|
||||
static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"};
|
||||
static SOC_ENUM_SINGLE_DECL(diffmux,
|
||||
ES8328_ADCCONTROL3, 7, es8328_diff_sel);
|
||||
static const struct snd_kcontrol_new es8328_diffmux_controls =
|
||||
SOC_DAPM_ENUM("Route", diffmux);
|
||||
|
||||
/* Mono ADC Mux */
|
||||
static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)",
|
||||
"Mono (Right)", "Digital Mono"};
|
||||
static SOC_ENUM_SINGLE_DECL(monomux,
|
||||
ES8328_ADCCONTROL3, 3, es8328_mono_mux);
|
||||
static const struct snd_kcontrol_new es8328_monomux_controls =
|
||||
SOC_DAPM_ENUM("Route", monomux);
|
||||
|
||||
static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_diffmux_controls),
|
||||
SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_monomux_controls),
|
||||
SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_monomux_controls),
|
||||
|
||||
SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_AINL_OFF, 1,
|
||||
&es8328_left_pga_controls),
|
||||
SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_AINR_OFF, 1,
|
||||
&es8328_right_pga_controls),
|
||||
|
||||
SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_left_line_controls),
|
||||
SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_right_line_controls),
|
||||
|
||||
SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_ADCR_OFF, 1),
|
||||
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_ADCL_OFF, 1),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER,
|
||||
ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER,
|
||||
ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_RDAC_OFF, 1),
|
||||
SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_LDAC_OFF, 1),
|
||||
|
||||
SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_left_mixer_controls[0],
|
||||
ARRAY_SIZE(es8328_left_mixer_controls)),
|
||||
SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
|
||||
&es8328_right_mixer_controls[0],
|
||||
ARRAY_SIZE(es8328_right_mixer_controls)),
|
||||
|
||||
SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER,
|
||||
ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LOUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT1"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUT2"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT2"),
|
||||
|
||||
SND_SOC_DAPM_INPUT("LINPUT1"),
|
||||
SND_SOC_DAPM_INPUT("LINPUT2"),
|
||||
SND_SOC_DAPM_INPUT("RINPUT1"),
|
||||
SND_SOC_DAPM_INPUT("RINPUT2"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
|
||||
|
||||
{ "Left Line Mux", "Line 1", "LINPUT1" },
|
||||
{ "Left Line Mux", "Line 2", "LINPUT2" },
|
||||
{ "Left Line Mux", "PGA", "Left PGA Mux" },
|
||||
{ "Left Line Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Right Line Mux", "Line 1", "RINPUT1" },
|
||||
{ "Right Line Mux", "Line 2", "RINPUT2" },
|
||||
{ "Right Line Mux", "PGA", "Right PGA Mux" },
|
||||
{ "Right Line Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Left PGA Mux", "Line 1", "LINPUT1" },
|
||||
{ "Left PGA Mux", "Line 2", "LINPUT2" },
|
||||
{ "Left PGA Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Right PGA Mux", "Line 1", "RINPUT1" },
|
||||
{ "Right PGA Mux", "Line 2", "RINPUT2" },
|
||||
{ "Right PGA Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Differential Mux", "Line 1", "LINPUT1" },
|
||||
{ "Differential Mux", "Line 1", "RINPUT1" },
|
||||
{ "Differential Mux", "Line 2", "LINPUT2" },
|
||||
{ "Differential Mux", "Line 2", "RINPUT2" },
|
||||
|
||||
{ "Left ADC Mux", "Stereo", "Left PGA Mux" },
|
||||
{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
|
||||
{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
|
||||
|
||||
{ "Right ADC Mux", "Stereo", "Right PGA Mux" },
|
||||
{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
|
||||
{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
|
||||
|
||||
{ "Left ADC", NULL, "Left ADC Mux" },
|
||||
{ "Right ADC", NULL, "Right ADC Mux" },
|
||||
|
||||
{ "ADC DIG", NULL, "ADC STM" },
|
||||
{ "ADC DIG", NULL, "ADC Vref" },
|
||||
{ "ADC DIG", NULL, "ADC DLL" },
|
||||
|
||||
{ "Left ADC", NULL, "ADC DIG" },
|
||||
{ "Right ADC", NULL, "ADC DIG" },
|
||||
|
||||
{ "Mic Bias", NULL, "Mic Bias Gen" },
|
||||
|
||||
{ "Left Line Mux", "Line 1", "LINPUT1" },
|
||||
{ "Left Line Mux", "Line 2", "LINPUT2" },
|
||||
{ "Left Line Mux", "PGA", "Left PGA Mux" },
|
||||
{ "Left Line Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Right Line Mux", "Line 1", "RINPUT1" },
|
||||
{ "Right Line Mux", "Line 2", "RINPUT2" },
|
||||
{ "Right Line Mux", "PGA", "Right PGA Mux" },
|
||||
{ "Right Line Mux", "Differential", "Differential Mux" },
|
||||
|
||||
{ "Left Out 1", NULL, "Left DAC" },
|
||||
{ "Right Out 1", NULL, "Right DAC" },
|
||||
{ "Left Out 2", NULL, "Left DAC" },
|
||||
{ "Right Out 2", NULL, "Right DAC" },
|
||||
|
||||
{ "Left Mixer", "Playback Switch", "Left DAC" },
|
||||
{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
|
||||
{ "Left Mixer", "Right Playback Switch", "Right DAC" },
|
||||
{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
|
||||
|
||||
{ "Right Mixer", "Left Playback Switch", "Left DAC" },
|
||||
{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
|
||||
{ "Right Mixer", "Playback Switch", "Right DAC" },
|
||||
{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
|
||||
|
||||
{ "DAC DIG", NULL, "DAC STM" },
|
||||
{ "DAC DIG", NULL, "DAC Vref" },
|
||||
{ "DAC DIG", NULL, "DAC DLL" },
|
||||
|
||||
{ "Left DAC", NULL, "DAC DIG" },
|
||||
{ "Right DAC", NULL, "DAC DIG" },
|
||||
|
||||
{ "Left Out 1", NULL, "Left Mixer" },
|
||||
{ "LOUT1", NULL, "Left Out 1" },
|
||||
{ "Right Out 1", NULL, "Right Mixer" },
|
||||
{ "ROUT1", NULL, "Right Out 1" },
|
||||
|
||||
{ "Left Out 2", NULL, "Left Mixer" },
|
||||
{ "LOUT2", NULL, "Left Out 2" },
|
||||
{ "Right Out 2", NULL, "Right Mixer" },
|
||||
{ "ROUT2", NULL, "Right Out 2" },
|
||||
};
|
||||
|
||||
static int es8328_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3,
|
||||
ES8328_DACCONTROL3_DACMUTE,
|
||||
mute ? ES8328_DACCONTROL3_DACMUTE : 0);
|
||||
}
|
||||
|
||||
static int es8328_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
int clk_rate;
|
||||
int i;
|
||||
int reg;
|
||||
u8 ratio;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = ES8328_DACCONTROL2;
|
||||
else
|
||||
reg = ES8328_ADCCONTROL5;
|
||||
|
||||
clk_rate = clk_get_rate(es8328->clk);
|
||||
|
||||
if ((clk_rate != ES8328_SYSCLK_RATE_1X) &&
|
||||
(clk_rate != ES8328_SYSCLK_RATE_2X)) {
|
||||
dev_err(codec->dev,
|
||||
"%s: clock is running at %d Hz, not %d or %d Hz\n",
|
||||
__func__, clk_rate,
|
||||
ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* find master mode MCLK to sampling frequency ratio */
|
||||
ratio = mclk_ratios[0].rate;
|
||||
for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++)
|
||||
if (params_rate(params) <= mclk_ratios[i].rate)
|
||||
ratio = mclk_ratios[i].ratio;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
es8328->playback_fs = params_rate(params);
|
||||
es8328_set_deemph(codec);
|
||||
}
|
||||
|
||||
return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
|
||||
}
|
||||
|
||||
static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
int clk_rate;
|
||||
u8 mode = ES8328_DACCONTROL1_DACWL_16;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
|
||||
return -EINVAL;
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clock inversion */
|
||||
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
|
||||
return -EINVAL;
|
||||
|
||||
snd_soc_write(codec, ES8328_DACCONTROL1, mode);
|
||||
snd_soc_write(codec, ES8328_ADCCONTROL4, mode);
|
||||
|
||||
/* Master serial port mode, with BCLK generated automatically */
|
||||
clk_rate = clk_get_rate(es8328->clk);
|
||||
if (clk_rate == ES8328_SYSCLK_RATE_1X)
|
||||
snd_soc_write(codec, ES8328_MASTERMODE,
|
||||
ES8328_MASTERMODE_MSC);
|
||||
else
|
||||
snd_soc_write(codec, ES8328_MASTERMODE,
|
||||
ES8328_MASTERMODE_MCLKDIV2 |
|
||||
ES8328_MASTERMODE_MSC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8328_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* VREF, VMID=2x50k, digital enabled */
|
||||
snd_soc_write(codec, ES8328_CHIPPOWER, 0);
|
||||
snd_soc_update_bits(codec, ES8328_CONTROL1,
|
||||
ES8328_CONTROL1_VMIDSEL_MASK |
|
||||
ES8328_CONTROL1_ENREF,
|
||||
ES8328_CONTROL1_VMIDSEL_50k |
|
||||
ES8328_CONTROL1_ENREF);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
snd_soc_update_bits(codec, ES8328_CONTROL1,
|
||||
ES8328_CONTROL1_VMIDSEL_MASK |
|
||||
ES8328_CONTROL1_ENREF,
|
||||
ES8328_CONTROL1_VMIDSEL_5k |
|
||||
ES8328_CONTROL1_ENREF);
|
||||
|
||||
/* Charge caps */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
snd_soc_write(codec, ES8328_CONTROL2,
|
||||
ES8328_CONTROL2_OVERCURRENT_ON |
|
||||
ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
|
||||
|
||||
/* VREF, VMID=2*500k, digital stopped */
|
||||
snd_soc_update_bits(codec, ES8328_CONTROL1,
|
||||
ES8328_CONTROL1_VMIDSEL_MASK |
|
||||
ES8328_CONTROL1_ENREF,
|
||||
ES8328_CONTROL1_VMIDSEL_500k |
|
||||
ES8328_CONTROL1_ENREF);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, ES8328_CONTROL1,
|
||||
ES8328_CONTROL1_VMIDSEL_MASK |
|
||||
ES8328_CONTROL1_ENREF,
|
||||
0);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops es8328_dai_ops = {
|
||||
.hw_params = es8328_hw_params,
|
||||
.digital_mute = es8328_mute,
|
||||
.set_fmt = es8328_set_dai_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver es8328_dai = {
|
||||
.name = "es8328-hifi-analog",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ES8328_RATES,
|
||||
.formats = ES8328_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = ES8328_RATES,
|
||||
.formats = ES8328_FORMATS,
|
||||
},
|
||||
.ops = &es8328_dai_ops,
|
||||
};
|
||||
|
||||
static int es8328_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct es8328_priv *es8328;
|
||||
int ret;
|
||||
|
||||
es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
clk_disable_unprepare(es8328->clk);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to disable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8328_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
|
||||
struct es8328_priv *es8328;
|
||||
int ret;
|
||||
|
||||
es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = clk_prepare_enable(es8328->clk);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_mark_dirty(regmap);
|
||||
ret = regcache_sync(regmap);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to sync regcache\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8328_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct es8328_priv *es8328;
|
||||
int ret;
|
||||
|
||||
es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clocks */
|
||||
es8328->clk = devm_clk_get(codec->dev, NULL);
|
||||
if (IS_ERR(es8328->clk)) {
|
||||
dev_err(codec->dev, "codec clock missing or invalid\n");
|
||||
ret = PTR_ERR(es8328->clk);
|
||||
goto clk_fail;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(es8328->clk);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "unable to prepare codec clk\n");
|
||||
goto clk_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clk_fail:
|
||||
regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int es8328_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct es8328_priv *es8328;
|
||||
|
||||
es8328 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (es8328->clk)
|
||||
clk_disable_unprepare(es8328->clk);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct regmap_config es8328_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = ES8328_REG_MAX,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(es8328_regmap_config);
|
||||
|
||||
static struct snd_soc_codec_driver es8328_codec_driver = {
|
||||
.probe = es8328_codec_probe,
|
||||
.suspend = es8328_suspend,
|
||||
.resume = es8328_resume,
|
||||
.remove = es8328_remove,
|
||||
.set_bias_level = es8328_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = es8328_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(es8328_snd_controls),
|
||||
.dapm_widgets = es8328_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets),
|
||||
.dapm_routes = es8328_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes),
|
||||
};
|
||||
|
||||
int es8328_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct es8328_priv *es8328;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL);
|
||||
if (es8328 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
es8328->regmap = regmap;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
|
||||
es8328->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies),
|
||||
es8328->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to get regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, es8328);
|
||||
|
||||
return snd_soc_register_codec(dev,
|
||||
&es8328_codec_driver, &es8328_dai, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(es8328_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ES8328 driver");
|
||||
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
314
sound/soc/codecs/es8328.h
Normal file
314
sound/soc/codecs/es8328.h
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* es8328.h -- ES8328 ALSA SoC Audio driver
|
||||
*/
|
||||
|
||||
#ifndef _ES8328_H
|
||||
#define _ES8328_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device;
|
||||
|
||||
extern const struct regmap_config es8328_regmap_config;
|
||||
int es8328_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
#define ES8328_DACLVOL 46
|
||||
#define ES8328_DACRVOL 47
|
||||
#define ES8328_DACCTL 28
|
||||
#define ES8328_RATEMASK (0x1f << 0)
|
||||
|
||||
#define ES8328_CONTROL1 0x00
|
||||
#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
|
||||
#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
|
||||
#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
|
||||
#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
|
||||
#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0)
|
||||
#define ES8328_CONTROL1_ENREF (1 << 2)
|
||||
#define ES8328_CONTROL1_SEQEN (1 << 3)
|
||||
#define ES8328_CONTROL1_SAMEFS (1 << 4)
|
||||
#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
|
||||
#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
|
||||
#define ES8328_CONTROL1_LRCM (1 << 6)
|
||||
#define ES8328_CONTROL1_SCP_RESET (1 << 7)
|
||||
|
||||
#define ES8328_CONTROL2 0x01
|
||||
#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
|
||||
#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
|
||||
#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
|
||||
#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
|
||||
#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
|
||||
#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
|
||||
#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
|
||||
#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
|
||||
|
||||
#define ES8328_CHIPPOWER 0x02
|
||||
#define ES8328_CHIPPOWER_DACVREF_OFF 0
|
||||
#define ES8328_CHIPPOWER_ADCVREF_OFF 1
|
||||
#define ES8328_CHIPPOWER_DACDLL_OFF 2
|
||||
#define ES8328_CHIPPOWER_ADCDLL_OFF 3
|
||||
#define ES8328_CHIPPOWER_DACSTM_RESET 4
|
||||
#define ES8328_CHIPPOWER_ADCSTM_RESET 5
|
||||
#define ES8328_CHIPPOWER_DACDIG_OFF 6
|
||||
#define ES8328_CHIPPOWER_ADCDIG_OFF 7
|
||||
|
||||
#define ES8328_ADCPOWER 0x03
|
||||
#define ES8328_ADCPOWER_INT1_LOWPOWER 0
|
||||
#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1
|
||||
#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2
|
||||
#define ES8328_ADCPOWER_MIC_BIAS_OFF 3
|
||||
#define ES8328_ADCPOWER_ADCR_OFF 4
|
||||
#define ES8328_ADCPOWER_ADCL_OFF 5
|
||||
#define ES8328_ADCPOWER_AINR_OFF 6
|
||||
#define ES8328_ADCPOWER_AINL_OFF 7
|
||||
|
||||
#define ES8328_DACPOWER 0x04
|
||||
#define ES8328_DACPOWER_OUT3_ON 0
|
||||
#define ES8328_DACPOWER_MONO_ON 1
|
||||
#define ES8328_DACPOWER_ROUT2_ON 2
|
||||
#define ES8328_DACPOWER_LOUT2_ON 3
|
||||
#define ES8328_DACPOWER_ROUT1_ON 4
|
||||
#define ES8328_DACPOWER_LOUT1_ON 5
|
||||
#define ES8328_DACPOWER_RDAC_OFF 6
|
||||
#define ES8328_DACPOWER_LDAC_OFF 7
|
||||
|
||||
#define ES8328_CHIPLOPOW1 0x05
|
||||
#define ES8328_CHIPLOPOW2 0x06
|
||||
#define ES8328_ANAVOLMANAG 0x07
|
||||
|
||||
#define ES8328_MASTERMODE 0x08
|
||||
#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
|
||||
#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
|
||||
#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
|
||||
#define ES8328_MASTERMODE_MSC (1 << 7)
|
||||
|
||||
#define ES8328_ADCCONTROL1 0x09
|
||||
#define ES8328_ADCCONTROL2 0x0a
|
||||
#define ES8328_ADCCONTROL3 0x0b
|
||||
#define ES8328_ADCCONTROL4 0x0c
|
||||
#define ES8328_ADCCONTROL5 0x0d
|
||||
#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
|
||||
|
||||
#define ES8328_ADCCONTROL6 0x0e
|
||||
|
||||
#define ES8328_ADCCONTROL7 0x0f
|
||||
#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
|
||||
#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
|
||||
#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
|
||||
#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
|
||||
#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
|
||||
#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
|
||||
#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
|
||||
#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
|
||||
|
||||
#define ES8328_ADCCONTROL8 0x10
|
||||
#define ES8328_ADCCONTROL9 0x11
|
||||
#define ES8328_ADCCONTROL10 0x12
|
||||
#define ES8328_ADCCONTROL11 0x13
|
||||
#define ES8328_ADCCONTROL12 0x14
|
||||
#define ES8328_ADCCONTROL13 0x15
|
||||
#define ES8328_ADCCONTROL14 0x16
|
||||
|
||||
#define ES8328_DACCONTROL1 0x17
|
||||
#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
|
||||
#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
|
||||
#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
|
||||
#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
|
||||
#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
|
||||
#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
|
||||
#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
|
||||
#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
|
||||
#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
|
||||
#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
|
||||
#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
|
||||
#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
|
||||
#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6)
|
||||
#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL2 0x18
|
||||
#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
|
||||
#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5)
|
||||
|
||||
#define ES8328_DACCONTROL3 0x19
|
||||
#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
|
||||
#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
|
||||
#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
|
||||
#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
|
||||
#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
|
||||
#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
|
||||
|
||||
#define ES8328_LDACVOL 0x1a
|
||||
#define ES8328_LDACVOL_MASK (0 << 0)
|
||||
#define ES8328_LDACVOL_MAX (0xc0)
|
||||
|
||||
#define ES8328_RDACVOL 0x1b
|
||||
#define ES8328_RDACVOL_MASK (0 << 0)
|
||||
#define ES8328_RDACVOL_MAX (0xc0)
|
||||
|
||||
#define ES8328_DACVOL_MAX (0xc0)
|
||||
|
||||
#define ES8328_DACCONTROL4 0x1a
|
||||
#define ES8328_DACCONTROL5 0x1b
|
||||
|
||||
#define ES8328_DACCONTROL6 0x1c
|
||||
#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
|
||||
#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
|
||||
#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
|
||||
#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
|
||||
#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
|
||||
#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
|
||||
#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
|
||||
|
||||
#define ES8328_DACCONTROL7 0x1d
|
||||
#define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0)
|
||||
#define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0)
|
||||
#define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0)
|
||||
#define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0)
|
||||
#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */
|
||||
#define ES8328_DACCONTROL7_MONO (1 << 5)
|
||||
#define ES8328_DACCONTROL7_ZEROR (1 << 6)
|
||||
#define ES8328_DACCONTROL7_ZEROL (1 << 7)
|
||||
|
||||
/* Shelving filter */
|
||||
#define ES8328_DACCONTROL8 0x1e
|
||||
#define ES8328_DACCONTROL9 0x1f
|
||||
#define ES8328_DACCONTROL10 0x20
|
||||
#define ES8328_DACCONTROL11 0x21
|
||||
#define ES8328_DACCONTROL12 0x22
|
||||
#define ES8328_DACCONTROL13 0x23
|
||||
#define ES8328_DACCONTROL14 0x24
|
||||
#define ES8328_DACCONTROL15 0x25
|
||||
|
||||
#define ES8328_DACCONTROL16 0x26
|
||||
#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
|
||||
#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
|
||||
#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
|
||||
#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
|
||||
#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
|
||||
#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
|
||||
#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
|
||||
#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
|
||||
|
||||
#define ES8328_DACCONTROL17 0x27
|
||||
#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL17_LI2LO (1 << 6)
|
||||
#define ES8328_DACCONTROL17_LD2LO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL18 0x28
|
||||
#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL18_RI2LO (1 << 6)
|
||||
#define ES8328_DACCONTROL18_RD2LO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL19 0x29
|
||||
#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL19_LI2RO (1 << 6)
|
||||
#define ES8328_DACCONTROL19_LD2RO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL20 0x2a
|
||||
#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL20_RI2RO (1 << 6)
|
||||
#define ES8328_DACCONTROL20_RD2RO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL21 0x2b
|
||||
#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL21_LI2MO (1 << 6)
|
||||
#define ES8328_DACCONTROL21_LD2MO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL22 0x2c
|
||||
#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3)
|
||||
#define ES8328_DACCONTROL22_RI2MO (1 << 6)
|
||||
#define ES8328_DACCONTROL22_RD2MO (1 << 7)
|
||||
|
||||
#define ES8328_DACCONTROL23 0x2d
|
||||
#define ES8328_DACCONTROL23_MOUTINV (1 << 1)
|
||||
#define ES8328_DACCONTROL23_HPSWPOL (1 << 2)
|
||||
#define ES8328_DACCONTROL23_HPSWEN (1 << 3)
|
||||
#define ES8328_DACCONTROL23_VROI_1p5k (0 << 4)
|
||||
#define ES8328_DACCONTROL23_VROI_40k (1 << 4)
|
||||
#define ES8328_DACCONTROL23_OUT3_VREF (0 << 5)
|
||||
#define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5)
|
||||
#define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5)
|
||||
#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5)
|
||||
#define ES8328_DACCONTROL23_ROUT2INV (1 << 7)
|
||||
|
||||
/* LOUT1 Amplifier */
|
||||
#define ES8328_LOUT1VOL 0x2e
|
||||
#define ES8328_LOUT1VOL_MASK (0 << 5)
|
||||
#define ES8328_LOUT1VOL_MAX (0x24)
|
||||
|
||||
/* ROUT1 Amplifier */
|
||||
#define ES8328_ROUT1VOL 0x2f
|
||||
#define ES8328_ROUT1VOL_MASK (0 << 5)
|
||||
#define ES8328_ROUT1VOL_MAX (0x24)
|
||||
|
||||
#define ES8328_OUT1VOL_MAX (0x24)
|
||||
|
||||
/* LOUT2 Amplifier */
|
||||
#define ES8328_LOUT2VOL 0x30
|
||||
#define ES8328_LOUT2VOL_MASK (0 << 5)
|
||||
#define ES8328_LOUT2VOL_MAX (0x24)
|
||||
|
||||
/* ROUT2 Amplifier */
|
||||
#define ES8328_ROUT2VOL 0x31
|
||||
#define ES8328_ROUT2VOL_MASK (0 << 5)
|
||||
#define ES8328_ROUT2VOL_MAX (0x24)
|
||||
|
||||
#define ES8328_OUT2VOL_MAX (0x24)
|
||||
|
||||
/* Mono Out Amplifier */
|
||||
#define ES8328_MONOOUTVOL 0x32
|
||||
#define ES8328_MONOOUTVOL_MASK (0 << 5)
|
||||
#define ES8328_MONOOUTVOL_MAX (0x24)
|
||||
|
||||
#define ES8328_DACCONTROL29 0x33
|
||||
#define ES8328_DACCONTROL30 0x34
|
||||
|
||||
#define ES8328_SYSCLK 0
|
||||
|
||||
#define ES8328_REG_MAX 0x35
|
||||
|
||||
#define ES8328_PLL1 0
|
||||
#define ES8328_PLL2 1
|
||||
|
||||
/* clock inputs */
|
||||
#define ES8328_MCLK 0
|
||||
#define ES8328_PCMCLK 1
|
||||
|
||||
/* clock divider id's */
|
||||
#define ES8328_PCMDIV 0
|
||||
#define ES8328_BCLKDIV 1
|
||||
#define ES8328_VXCLKDIV 2
|
||||
|
||||
/* PCM clock dividers */
|
||||
#define ES8328_PCM_DIV_1 (0 << 6)
|
||||
#define ES8328_PCM_DIV_3 (2 << 6)
|
||||
#define ES8328_PCM_DIV_5_5 (3 << 6)
|
||||
#define ES8328_PCM_DIV_2 (4 << 6)
|
||||
#define ES8328_PCM_DIV_4 (5 << 6)
|
||||
#define ES8328_PCM_DIV_6 (6 << 6)
|
||||
#define ES8328_PCM_DIV_8 (7 << 6)
|
||||
|
||||
/* BCLK clock dividers */
|
||||
#define ES8328_BCLK_DIV_1 (0 << 7)
|
||||
#define ES8328_BCLK_DIV_2 (1 << 7)
|
||||
#define ES8328_BCLK_DIV_4 (2 << 7)
|
||||
#define ES8328_BCLK_DIV_8 (3 << 7)
|
||||
|
||||
/* VXCLK clock dividers */
|
||||
#define ES8328_VXCLK_DIV_1 (0 << 6)
|
||||
#define ES8328_VXCLK_DIV_2 (1 << 6)
|
||||
#define ES8328_VXCLK_DIV_4 (2 << 6)
|
||||
#define ES8328_VXCLK_DIV_8 (3 << 6)
|
||||
#define ES8328_VXCLK_DIV_16 (4 << 6)
|
||||
|
||||
#define ES8328_DAI_HIFI 0
|
||||
#define ES8328_DAI_VOICE 1
|
||||
|
||||
#define ES8328_1536FS 1536
|
||||
#define ES8328_1024FS 1024
|
||||
#define ES8328_768FS 768
|
||||
#define ES8328_512FS 512
|
||||
#define ES8328_384FS 384
|
||||
#define ES8328_256FS 256
|
||||
#define ES8328_128FS 128
|
||||
|
||||
#endif
|
||||
356
sound/soc/codecs/exynos-audmixer-regs.h
Normal file
356
sound/soc/codecs/exynos-audmixer-regs.h
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/**
|
||||
* Copyright 2015 Samsung Electronics Co. Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _AUDMIXER_REGISTERS_H
|
||||
#define _AUDMIXER_REGISTERS_H
|
||||
|
||||
/**
|
||||
* The register offsets in APB-based Audio Mixers are 4 times those in I2C-based
|
||||
* Audio Mixers. To handle this, we have used SoC type based multiplier.
|
||||
* TODO: Need to find a better way to do this.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SOC_EXYNOS7580
|
||||
#define AUDMIXER_REG_MULT 1
|
||||
#else
|
||||
#define AUDMIXER_REG_MULT 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Register addresses
|
||||
*/
|
||||
#define AUDMIXER_REG_00_SOFT_RSTB (0x00 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_01_IN1_CTL1 (0x01 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_02_IN1_CTL2 (0x02 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_03_IN1_CTL3 (0x03 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_04_IN2_CTL1 (0x04 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_05_IN2_CTL2 (0x05 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_06_IN2_CTL3 (0x06 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_07_IN3_CTL1 (0x07 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_08_IN3_CTL2 (0x08 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_09_IN3_CTL3 (0x09 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0A_HQ_CTL (0x0a * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0B_SLOT_L (0x0b * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0C_SLOT_R (0x0c * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0D_RMIX_CTL (0x0d * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0E_TSLOT (0x0e * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_0F_DIG_EN (0x0f * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_10_DMIX1 (0x10 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_11_DMIX2 (0x11 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_16_DOUTMX1 (0x16 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_17_DOUTMX2 (0x17 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_18_INAMP_CTL (0x18 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_19_OUTAP1_CTL (0x19 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_1A_OUTCP1_CTL (0x1a * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_68_ALC_CTL (0x68 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_69_ALC_GA1 (0x69 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6A_ALC_GA2 (0x6a * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6B_ALC_LVL (0x6b * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6C_ALC_LVR (0x6c * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6D_ALC_HLD (0x6d * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6E_ALC_ATK (0x6e * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_6F_ALC_DCY (0x6f * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_70_ALC_NG (0x70 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_71_ALC_SGL (0x71 * AUDMIXER_REG_MULT)
|
||||
#define AUDMIXER_REG_72_ALC_SGR (0x72 * AUDMIXER_REG_MULT)
|
||||
|
||||
#define AUDMIXER_MAX_REGISTER AUDMIXER_REG_72_ALC_SGR
|
||||
|
||||
/**
|
||||
* Description of bit-fields of various registers
|
||||
*/
|
||||
|
||||
/* AUDMIXER_REG_00_SOFT_RSTB */
|
||||
#define SOFT_RSTB_DATA_RSTB_SHIFT 1
|
||||
#define SOFT_RSTB_SYS_RSTB_SHIFT 0
|
||||
|
||||
/**
|
||||
* AUDMIXER_REG_01_IN1_CTL1
|
||||
* AUDMIXER_REG_04_IN2_CTL1
|
||||
* AUDMIXER_REG_07_IN3_CTL1
|
||||
*/
|
||||
#define INCTL1_MPCM_SRATE_SHIFT 5
|
||||
#define INCTL1_MPCM_SRATE_MASK 0x3
|
||||
#define INCTL1_MASTER_SHIFT 4
|
||||
#define INCTL1_MPCM_SLOT_SHIFT 2
|
||||
#define INCTL1_MPCM_SLOT_MASK 0x3
|
||||
#define INCTL1_BCK_POL_SHIFT 1
|
||||
#define INCTL1_I2S_PCM_SHIFT 0
|
||||
|
||||
#define INCTL1_BT_OSYNC_POL_MASK 1
|
||||
#define INCTL1_BT_OSYNC_POL_SHIFT 2
|
||||
#define INCTL1_ISYNC_POL_MASK 1
|
||||
#define INCTL1_ISYNC_POL_SHIFT 1
|
||||
#define INCTL1_FM_BT_SEL_MASK 1
|
||||
#define INCTL1_FM_BT_SEL_SHIFT 0
|
||||
|
||||
#define MPCM_SRATE_32KHZ 0x3
|
||||
#define MPCM_SRATE_24KHZ 0x2
|
||||
#define MPCM_SRATE_16KHZ 0x1
|
||||
#define MPCM_SRATE_8KHZ 0x0
|
||||
|
||||
#define MIXER_MASTER 1
|
||||
#define MIXER_SLAVE 0
|
||||
|
||||
#define MPCM_SLOT_64BCK 3
|
||||
#define MPCM_SLOT_48BCK 2
|
||||
#define MPCM_SLOT_32BCK 1
|
||||
#define MPCM_SLOT_16BCK 0
|
||||
|
||||
#define BCK_POL_INVERTED 1
|
||||
#define BCK_POL_NORMAL 0
|
||||
|
||||
#define I2S_PCM_MODE_PCM 1
|
||||
#define I2S_PCM_MODE_I2S 0
|
||||
|
||||
/* AUDMIXER_REG_02_IN1_CTL2 */
|
||||
/* AUDMIXER_REG_05_IN2_CTL2 */
|
||||
/* AUDMIXER_REG_08_IN3_CTL2 */
|
||||
#define INCTL2_I2S_XFS_SHIFT 5
|
||||
#define INCTL2_I2S_XFS_MASK 0x3
|
||||
#define INCTL2_LRCK_POL_SHIFT 4
|
||||
#define INCTL2_I2S_DF_SHIFT 2
|
||||
#define INCTL2_I2S_DF_MASK 0x3
|
||||
#define INCTL2_I2S_DL_SHIFT 0
|
||||
#define INCTL2_I2S_DL_MASK 0x3
|
||||
|
||||
#define I2S_XFS_64FS 2
|
||||
#define I2S_XFS_48FS 1
|
||||
#define I2S_XFS_32FS 0
|
||||
|
||||
#define LRCLK_POL_RIGHT 1
|
||||
#define LRCLK_POL_LEFT 0
|
||||
|
||||
#define I2S_DF_RJ 2
|
||||
#define I2S_DF_LJ 1
|
||||
#define I2S_DF_I2S 0
|
||||
|
||||
#define I2S_DL_24BIT 3
|
||||
#define I2S_DL_20BIT 2
|
||||
#define I2S_DL_18BIT 1
|
||||
#define I2S_DL_16BIT 0
|
||||
|
||||
/* AUDMIXER_REG_03_IN1_CTL3 */
|
||||
/* AUDMIXER_REG_06_IN2_CTL3 */
|
||||
/* AUDMIXER_REG_09_IN3_CTL3 */
|
||||
#define INCTL3_PCM_DAD_SHIFT 5
|
||||
#define INCTL3_PCM_DAD_MASK 0x3
|
||||
#define INCTL3_PCM_DF_SHIFT 0
|
||||
#define INCTL3_PCM_DF_MASK 0xf
|
||||
|
||||
#define PCM_DAD_4BCK 6
|
||||
#define PCM_DAD_3BCK 4
|
||||
#define PCM_DAD_2BCK 2
|
||||
#define PCM_DAD_0BCK 1
|
||||
#define PCM_DAD_1BCK 0
|
||||
|
||||
#define PCM_DF_SHORT_FRAME 4
|
||||
#define PCM_DF_LONG_FRAME 0xc
|
||||
|
||||
/* AUDMIXER_REG_0A_HQ_CTL */
|
||||
#define HQ_CTL_CH3_SEL_SHIFT 3
|
||||
#define HQ_CTL_MCKO_EN_SHIFT 2
|
||||
#define HQ_CTL_BCK4_MODE_SHIFT 1
|
||||
#define HQ_CTL_HQ_EN_SHIFT 0
|
||||
#define HQ_CTL_HQ_EN_MASK BIT(HQ_CTL_HQ_EN_SHIFT)
|
||||
|
||||
/* AUDMIXER_REG_0B_SLOT_L */
|
||||
#define SLOT_L_SEL_SHIFT 0
|
||||
#define SLOT_L_SEL_MASK 0xf
|
||||
|
||||
/* AUDMIXER_REG_0C_SLOT_R */
|
||||
#define SLOT_R_SEL_SHIFT 0
|
||||
#define SLOT_R_SEL_MASK 0xf
|
||||
|
||||
#define SLOT_SEL_1ST_SLOT 1
|
||||
#define SLOT_SEL_2ND_SLOT 2
|
||||
#define SLOT_SEL_3RD_SLOT 4
|
||||
#define SLOT_SEL_4TH_SLOT 8
|
||||
|
||||
/* AUDMIXER_REG_0D_RMIX_CTL */
|
||||
#define RMIX_CTL_RMIX2_EN_SHIFT 7
|
||||
#define RMIX_CTL_RMIX2_LVL_SHIFT 4
|
||||
#define RMIX_CTL_RMIX2_LVL_WIDTH 3
|
||||
#define RMIX_CTL_RMIX2_LVL_MASK 0x7
|
||||
#define RMIX_CTL_RMIX1_EN_SHIFT 3
|
||||
#define RMIX_CTL_RMIX1_LVL_SHIFT 0
|
||||
#define RMIX_CTL_RMIX1_LVL_WIDTH 3
|
||||
#define RMIX_CTL_RMIX1_LVL_MASK 0x7
|
||||
|
||||
/* AUDMIXER_REG_0E_TSLOT */
|
||||
#define TSLOT_SLOT_SHIFT 0
|
||||
#define TSLOT_SLOT_MASK 0x3
|
||||
|
||||
#define TSLOT_USED_4 3
|
||||
#define TSLOT_USED_3 2
|
||||
#define TSLOT_USED_2 1
|
||||
#define TSLOT_USED_1 0
|
||||
|
||||
/* AUDMIXER_REG_0F_DIG_EN */
|
||||
|
||||
#define DIG_EN_CP1_EN_SHIFT 5
|
||||
#define DIG_EN_AP1_EN_SHIFT 4
|
||||
#define DIG_EN_MIX_EN_SHIFT 3
|
||||
#define DIG_EN_SRC3_EN_SHIFT 2
|
||||
#define DIG_EN_SRC2_EN_SHIFT 1
|
||||
#define DIG_EN_SRC1_EN_SHIFT 0
|
||||
#define DIG_EN_AP0_EN_SHIFT 0
|
||||
#define DIG_EN_MASK 1
|
||||
|
||||
/* AUDMIXER_REG_10_DMIX1 */
|
||||
#define DMIX1_MIX_EN2_SHIFT 7
|
||||
#define DMIX1_MIX_LVL2_SHIFT 4
|
||||
#define DMIX1_MIX_LVL2_WIDTH 3
|
||||
#define DMIX1_MIX_LVL2_MASK 0x7
|
||||
#define DMIX1_MIX_EN1_SHIFT 3
|
||||
#define DMIX1_MIX_LVL1_SHIFT 0
|
||||
#define DMIX1_MIX_LVL1_WIDTH 3
|
||||
#define DMIX1_MIX_LVL1_MASK 0x7
|
||||
|
||||
/* AUDMIXER_REG_11_DMIX2 */
|
||||
#define DMIX2_MIX_EN4_SHIFT 7
|
||||
#define DMIX2_MIX_LVL4_SHIFT 4
|
||||
#define DMIX2_MIX_LVL4_WIDTH 3
|
||||
#define DMIX2_MIX_LVL4_MASK 0x7
|
||||
#define DMIX2_MIX_EN3_SHIFT 3
|
||||
#define DMIX2_MIX_LVL3_SHIFT 0
|
||||
#define DMIX2_MIX_LVL3_WIDTH 3
|
||||
#define DMIX2_MIX_LVL3_MASK 0x7
|
||||
|
||||
#define DMIX_EN_MASK 0x1
|
||||
|
||||
/* AUDMIXER_REG_16_DOUTMX1 */
|
||||
#define DOUTMX1_DOUT_SEL2_SHIFT 3
|
||||
#define DOUTMX1_DOUT_SEL2_MASK 0x7
|
||||
#define DOUTMX1_DOUT_SEL1_SHIFT 0
|
||||
#define DOUTMX1_DOUT_SEL1_MASK 0x7
|
||||
|
||||
#define DOUT_SEL2_BT_DATA 2
|
||||
#define DOUT_SEL2_ADC_DATA 1
|
||||
#define DOUT_SEL2_MIX_DATA 0
|
||||
|
||||
#define DOUT_SEL1_ADC_CP_DATA 2
|
||||
#define DOUT_SEL1_ADC_DATA 1
|
||||
#define DOUT_SEL1_MIX_DATA 0
|
||||
|
||||
/* AUDMIXER_REG_17_DOUTMX2 */
|
||||
#define DOUTMX2_DOUT_SEL3_SHIFT 0
|
||||
#define DOUTMX2_DOUT_SEL3_MASK 0x7
|
||||
|
||||
#define DOUT_SEL3_CP_DATA 2
|
||||
#define DOUT_SEL3_ADC_DATA 1
|
||||
#define DOUT_SEL3_MIX_DATA 0
|
||||
|
||||
/* AUDMIXER_REG_18_INAMP_CTL */
|
||||
#define INAMP_CTL_BCK_POL_SHIFT 7
|
||||
#define INAMP_CTL_BCK_POL_MASK 1
|
||||
|
||||
#define INAMP_CTL_LRCLK_POL_SHIFT 6
|
||||
#define INAMP_CTL_LRCLK_POL_MASK 1
|
||||
|
||||
#define INAMP_CTL_I2S_XFS_SHIFT 2
|
||||
#define INAMP_CTL_I2S_XFS_MASK 0x3
|
||||
|
||||
#define INAMP_CTL_I2S_DL_SHIFT 0
|
||||
#define INAMP_CTL_I2S_DL_MASK 0x3
|
||||
|
||||
/* AUDMIXER_REG_19_OUTAP1_CTL */
|
||||
/* AUDMIXER_REG_1A_OUTCP1_CTL */
|
||||
#define OUTAMP_CTL_LRCLK_POL_SHIFT 7
|
||||
#define OUTAMP_CTL_LRCLK_POL_MASK 1
|
||||
|
||||
#define OUTAMP_CTL_BCK_POL_SHIFT 6
|
||||
#define OUTAMP_CTL_BCK_POL_MASK 1
|
||||
|
||||
#define OUTAMP_CTL_I2S_DL_SHIFT 4
|
||||
#define OUTAMP_CTL_I2S_DL_MASK 0x3
|
||||
|
||||
#define OUTAMP_CTL_I2S_XFS_SHIFT 0
|
||||
#define OUTAMP_CTL_I2S_XFS_MASK 0x3
|
||||
|
||||
#define AMP_I2S_DL_24BIT 2
|
||||
#define AMP_I2S_DL_20BIT 1
|
||||
#define AMP_I2S_DL_16BIT 0
|
||||
|
||||
|
||||
/* AUDMIXER_REG_68_ALC_CTL */
|
||||
#define ALC_CTL_ALC_NG_HYS_SHIFT 6
|
||||
#define ALC_CTL_ALC_NG_HYS_WIDTH 2
|
||||
#define ALC_CTL_ALC_NG_HYS_MASK 0x3
|
||||
#define ALC_CTL_WINSEL_SHIFT 4
|
||||
#define ALC_CTL_WINSEL_MASK 0x3
|
||||
#define ALC_CTL_ALC_EN_SHIFT 3
|
||||
#define ALC_CTL_ALC_LIM_SHIFT 2
|
||||
#define ALC_CTL_ALC_MODE_SHIFT 0
|
||||
#define ALC_CTL_ALC_MODE_MASK 0x3
|
||||
|
||||
#define WINSEL_300FS 3
|
||||
#define WINSEL_2400FS 2
|
||||
#define WINSEL_1200FS 1
|
||||
#define WINSEL_600FS 0
|
||||
|
||||
#define ALC_MODE_RIGHT_LEFT_IND 3
|
||||
#define ALC_MODE_LEFT_CHAN 2
|
||||
#define ALC_MODE_RIGHT_CHAN 1
|
||||
#define ALC_MODE_STEREO 0
|
||||
|
||||
/* AUDMIXER_REG_69_ALC_GA1 */
|
||||
#define ALC_GA1_ALC_MAX_GAIN_SHIFT 0
|
||||
#define ALC_GA1_ALC_MAX_GAIN_MASK 0xff
|
||||
#define ALC_GA1_ALC_MAX_GAIN_MAXVAL 0x9c
|
||||
#define ALC_GA1_ALC_MAX_GAIN_MINVAL 0x6c
|
||||
|
||||
/* AUDMIXER_REG_6A_ALC_GA2 */
|
||||
#define ALC_GA2_ALC_MIN_GAIN_SHIFT 0
|
||||
#define ALC_GA2_ALC_MIN_GAIN_MASK 0xff
|
||||
#define ALC_GA2_ALC_MIN_GAIN_MAXVAL 0x6c
|
||||
#define ALC_GA2_ALC_MIN_GAIN_MINVAL 0x0
|
||||
|
||||
/* AUDMIXER_REG_6B_ALC_LVL */
|
||||
#define ALC_LVL_LVL_SHIFT 0
|
||||
#define ALC_LVL_LVL_WIDTH 5
|
||||
#define ALC_LVL_LVL_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_6C_ALC_LVR */
|
||||
#define ALC_LVR_LVL_SHIFT 0
|
||||
#define ALC_LVR_LVL_WIDTH 5
|
||||
#define ALC_LVR_LVL_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_6D_ALC_HLD */
|
||||
#define ALC_HLD_ALC_PATH_SEL_SHIFT 7
|
||||
#define ALC_HLD_ST_GAIN_EN_SHIFT 6
|
||||
#define ALC_HLD_HOLD_SHIFT 0
|
||||
#define ALC_HLD_HOLD_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_6E_ALC_ATK */
|
||||
#define ALC_ATK_ATTACK_SHIFT 0
|
||||
#define ALC_ATK_ATTACK_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_6F_ALC_DCY */
|
||||
#define ALC_DCY_DECAY_SHIFT 0
|
||||
#define ALC_DCY_DECAY_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_70_ALC_NG */
|
||||
#define ALC_NG_NGAT_SHIFT 7
|
||||
#define ALC_NG_ALCNGTH_SHIFT 0
|
||||
#define ALC_NG_ALCNGTH_WIDTH 5
|
||||
#define ALC_NG_ALCNGTH_MASK 0x1f
|
||||
|
||||
/* AUDMIXER_REG_71_ALC_SGL */
|
||||
#define ALC_SGL_START_GAIN_L_SHIFT 0
|
||||
#define ALC_SGL_START_GAIN_L_MASK 0xff
|
||||
#define ALC_SGL_START_GAIN_L_MAXVAL 0x9c
|
||||
#define ALC_SGL_START_GAIN_L_MINVAL 0x6c
|
||||
|
||||
/* AUDMIXER_REG_72_ALC_SGR */
|
||||
#define ALC_SGR_START_GAIN_R_SHIFT 0
|
||||
#define ALC_SGR_START_GAIN_R_MASK 0xff
|
||||
#define ALC_SGR_START_GAIN_R_MAXVAL 0x9c
|
||||
#define ALC_SGR_START_GAIN_R_MINVAL 0x6c
|
||||
|
||||
#endif
|
||||
2754
sound/soc/codecs/exynos-audmixer.c
Normal file
2754
sound/soc/codecs/exynos-audmixer.c
Normal file
File diff suppressed because it is too large
Load diff
108
sound/soc/codecs/hdmi.c
Normal file
108
sound/soc/codecs/hdmi.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* ALSA SoC codec driver for HDMI audio codecs.
|
||||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author: Ricardo Neri <ricardo.neri@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define DRV_NAME "hdmi-audio-codec"
|
||||
|
||||
static const struct snd_soc_dapm_widget hdmi_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("RX"),
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route hdmi_routes[] = {
|
||||
{ "Capture", NULL, "RX" },
|
||||
{ "TX", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver hdmi_codec_dai = {
|
||||
.name = "hdmi-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_32000 |
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id hdmi_audio_codec_ids[] = {
|
||||
{ .compatible = "linux,hdmi-audio", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
|
||||
#endif
|
||||
|
||||
static struct snd_soc_codec_driver hdmi_codec = {
|
||||
.dapm_widgets = hdmi_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
|
||||
.dapm_routes = hdmi_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
|
||||
};
|
||||
|
||||
static int hdmi_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &hdmi_codec,
|
||||
&hdmi_codec_dai, 1);
|
||||
}
|
||||
|
||||
static int hdmi_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hdmi_codec_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(hdmi_audio_codec_ids),
|
||||
},
|
||||
|
||||
.probe = hdmi_codec_probe,
|
||||
.remove = hdmi_codec_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(hdmi_codec_driver);
|
||||
|
||||
MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
|
||||
MODULE_DESCRIPTION("ASoC generic HDMI codec driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
1166
sound/soc/codecs/isabelle.c
Normal file
1166
sound/soc/codecs/isabelle.c
Normal file
File diff suppressed because it is too large
Load diff
143
sound/soc/codecs/isabelle.h
Normal file
143
sound/soc/codecs/isabelle.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* isabelle.h - Low power high fidelity audio codec driver header file
|
||||
*
|
||||
* Copyright (c) 2012 Texas Instruments, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISABELLE_H
|
||||
#define _ISABELLE_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* ISABELLE REGISTERS */
|
||||
|
||||
#define ISABELLE_PWR_CFG_REG 0x01
|
||||
#define ISABELLE_PWR_EN_REG 0x02
|
||||
#define ISABELLE_PS_EN1_REG 0x03
|
||||
#define ISABELLE_INT1_STATUS_REG 0x04
|
||||
#define ISABELLE_INT1_MASK_REG 0x05
|
||||
#define ISABELLE_INT2_STATUS_REG 0x06
|
||||
#define ISABELLE_INT2_MASK_REG 0x07
|
||||
#define ISABELLE_HKCTL1_REG 0x08
|
||||
#define ISABELLE_HKCTL2_REG 0x09
|
||||
#define ISABELLE_HKCTL3_REG 0x0A
|
||||
#define ISABELLE_ACCDET_STATUS_REG 0x0B
|
||||
#define ISABELLE_BUTTON_ID_REG 0x0C
|
||||
#define ISABELLE_PLL_CFG_REG 0x10
|
||||
#define ISABELLE_PLL_EN_REG 0x11
|
||||
#define ISABELLE_FS_RATE_CFG_REG 0x12
|
||||
#define ISABELLE_INTF_CFG_REG 0x13
|
||||
#define ISABELLE_INTF_EN_REG 0x14
|
||||
#define ISABELLE_ULATX12_INTF_CFG_REG 0x15
|
||||
#define ISABELLE_DL12_INTF_CFG_REG 0x16
|
||||
#define ISABELLE_DL34_INTF_CFG_REG 0x17
|
||||
#define ISABELLE_DL56_INTF_CFG_REG 0x18
|
||||
#define ISABELLE_ATX_STPGA1_CFG_REG 0x19
|
||||
#define ISABELLE_ATX_STPGA2_CFG_REG 0x1A
|
||||
#define ISABELLE_VTX_STPGA1_CFG_REG 0x1B
|
||||
#define ISABELLE_VTX2_STPGA2_CFG_REG 0x1C
|
||||
#define ISABELLE_ATX1_DPGA_REG 0x1D
|
||||
#define ISABELLE_ATX2_DPGA_REG 0x1E
|
||||
#define ISABELLE_VTX1_DPGA_REG 0x1F
|
||||
#define ISABELLE_VTX2_DPGA_REG 0x20
|
||||
#define ISABELLE_TX_INPUT_CFG_REG 0x21
|
||||
#define ISABELLE_RX_INPUT_CFG_REG 0x22
|
||||
#define ISABELLE_RX_INPUT_CFG2_REG 0x23
|
||||
#define ISABELLE_VOICE_HPF_CFG_REG 0x24
|
||||
#define ISABELLE_AUDIO_HPF_CFG_REG 0x25
|
||||
#define ISABELLE_RX1_DPGA_REG 0x26
|
||||
#define ISABELLE_RX2_DPGA_REG 0x27
|
||||
#define ISABELLE_RX3_DPGA_REG 0x28
|
||||
#define ISABELLE_RX4_DPGA_REG 0x29
|
||||
#define ISABELLE_RX5_DPGA_REG 0x2A
|
||||
#define ISABELLE_RX6_DPGA_REG 0x2B
|
||||
#define ISABELLE_ALU_TX_EN_REG 0x2C
|
||||
#define ISABELLE_ALU_RX_EN_REG 0x2D
|
||||
#define ISABELLE_IIR_RESYNC_REG 0x2E
|
||||
#define ISABELLE_ABIAS_CFG_REG 0x30
|
||||
#define ISABELLE_DBIAS_CFG_REG 0x31
|
||||
#define ISABELLE_MIC1_GAIN_REG 0x32
|
||||
#define ISABELLE_MIC2_GAIN_REG 0x33
|
||||
#define ISABELLE_AMIC_CFG_REG 0x34
|
||||
#define ISABELLE_DMIC_CFG_REG 0x35
|
||||
#define ISABELLE_APGA_GAIN_REG 0x36
|
||||
#define ISABELLE_APGA_CFG_REG 0x37
|
||||
#define ISABELLE_TX_GAIN_DLY_REG 0x38
|
||||
#define ISABELLE_RX_GAIN_DLY_REG 0x39
|
||||
#define ISABELLE_RX_PWR_CTRL_REG 0x3A
|
||||
#define ISABELLE_DPGA1LR_IN_SEL_REG 0x3B
|
||||
#define ISABELLE_DPGA1L_GAIN_REG 0x3C
|
||||
#define ISABELLE_DPGA1R_GAIN_REG 0x3D
|
||||
#define ISABELLE_DPGA2L_IN_SEL_REG 0x3E
|
||||
#define ISABELLE_DPGA2R_IN_SEL_REG 0x3F
|
||||
#define ISABELLE_DPGA2L_GAIN_REG 0x40
|
||||
#define ISABELLE_DPGA2R_GAIN_REG 0x41
|
||||
#define ISABELLE_DPGA3LR_IN_SEL_REG 0x42
|
||||
#define ISABELLE_DPGA3L_GAIN_REG 0x43
|
||||
#define ISABELLE_DPGA3R_GAIN_REG 0x44
|
||||
#define ISABELLE_DAC1_SOFTRAMP_REG 0x45
|
||||
#define ISABELLE_DAC2_SOFTRAMP_REG 0x46
|
||||
#define ISABELLE_DAC3_SOFTRAMP_REG 0x47
|
||||
#define ISABELLE_DAC_CFG_REG 0x48
|
||||
#define ISABELLE_EARDRV_CFG1_REG 0x49
|
||||
#define ISABELLE_EARDRV_CFG2_REG 0x4A
|
||||
#define ISABELLE_HSDRV_GAIN_REG 0x4B
|
||||
#define ISABELLE_HSDRV_CFG1_REG 0x4C
|
||||
#define ISABELLE_HSDRV_CFG2_REG 0x4D
|
||||
#define ISABELLE_HS_NG_CFG1_REG 0x4E
|
||||
#define ISABELLE_HS_NG_CFG2_REG 0x4F
|
||||
#define ISABELLE_LINEAMP_GAIN_REG 0x50
|
||||
#define ISABELLE_LINEAMP_CFG_REG 0x51
|
||||
#define ISABELLE_HFL_VOL_CTRL_REG 0x52
|
||||
#define ISABELLE_HFL_SFTVOL_CTRL_REG 0x53
|
||||
#define ISABELLE_HFL_LIM_CTRL_1_REG 0x54
|
||||
#define ISABELLE_HFL_LIM_CTRL_2_REG 0x55
|
||||
#define ISABELLE_HFR_VOL_CTRL_REG 0x56
|
||||
#define ISABELLE_HFR_SFTVOL_CTRL_REG 0x57
|
||||
#define ISABELLE_HFR_LIM_CTRL_1_REG 0x58
|
||||
#define ISABELLE_HFR_LIM_CTRL_2_REG 0x59
|
||||
#define ISABELLE_HF_MODE_REG 0x5A
|
||||
#define ISABELLE_HFLPGA_CFG_REG 0x5B
|
||||
#define ISABELLE_HFRPGA_CFG_REG 0x5C
|
||||
#define ISABELLE_HFDRV_CFG_REG 0x5D
|
||||
#define ISABELLE_PDMOUT_CFG1_REG 0x5E
|
||||
#define ISABELLE_PDMOUT_CFG2_REG 0x5F
|
||||
#define ISABELLE_PDMOUT_L_WM_REG 0x60
|
||||
#define ISABELLE_PDMOUT_R_WM_REG 0x61
|
||||
#define ISABELLE_HF_NG_CFG1_REG 0x62
|
||||
#define ISABELLE_HF_NG_CFG2_REG 0x63
|
||||
|
||||
/* ISABELLE_PWR_EN_REG (0x02h) */
|
||||
#define ISABELLE_CHIP_EN BIT(0)
|
||||
|
||||
/* ISABELLE DAI FORMATS */
|
||||
#define ISABELLE_AIF_FMT_MASK 0x70
|
||||
#define ISABELLE_I2S_MODE 0x0
|
||||
#define ISABELLE_LEFT_J_MODE 0x1
|
||||
#define ISABELLE_PDM_MODE 0x2
|
||||
|
||||
#define ISABELLE_AIF_LENGTH_MASK 0x30
|
||||
#define ISABELLE_AIF_LENGTH_20 0x00
|
||||
#define ISABELLE_AIF_LENGTH_32 0x10
|
||||
|
||||
#define ISABELLE_AIF_MS 0x80
|
||||
|
||||
#define ISABELLE_FS_RATE_MASK 0xF
|
||||
#define ISABELLE_FS_RATE_8 0x0
|
||||
#define ISABELLE_FS_RATE_11 0x1
|
||||
#define ISABELLE_FS_RATE_12 0x2
|
||||
#define ISABELLE_FS_RATE_16 0x4
|
||||
#define ISABELLE_FS_RATE_22 0x5
|
||||
#define ISABELLE_FS_RATE_24 0x6
|
||||
#define ISABELLE_FS_RATE_32 0x8
|
||||
#define ISABELLE_FS_RATE_44 0x9
|
||||
#define ISABELLE_FS_RATE_48 0xA
|
||||
|
||||
#define ISABELLE_MAX_REGISTER 0xFF
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue