mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 21:54:11 +08:00
Merge branch 'asoc-4.20' into asoc-next
This commit is contained in:
commit
65dfb6d6dd
54
Documentation/devicetree/bindings/sound/adi,adau1977.txt
Normal file
54
Documentation/devicetree/bindings/sound/adi,adau1977.txt
Normal file
@ -0,0 +1,54 @@
|
||||
Analog Devices ADAU1977/ADAU1978/ADAU1979
|
||||
|
||||
Datasheets:
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
|
||||
http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
|
||||
|
||||
This driver supports both the I2C and SPI bus.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
"adi,adau1977"
|
||||
"adi,adau1978"
|
||||
"adi,adau1979"
|
||||
|
||||
- AVDD-supply: analog power supply for the device, please consult
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Optional properties:
|
||||
- reset-gpio: the reset pin for the chip, for more details consult
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
|
||||
- DVDD-supply: supply voltage for the digital core, please consult
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
For required properties on SPI, please consult
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Required properties on I2C:
|
||||
|
||||
- reg: The i2c address. Value depends on the state of ADDR0
|
||||
and ADDR1, as wired in hardware.
|
||||
|
||||
Examples:
|
||||
|
||||
adau1977_spi: adau1977@0 {
|
||||
compatible = "adi,adau1977";
|
||||
spi-max-frequency = <600000>;
|
||||
|
||||
AVDD-supply = <®ulator>;
|
||||
DVDD-supply = <®ulator_digital>;
|
||||
|
||||
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
adau1977_i2c: adau1977@11 {
|
||||
compatible = "adi,adau1977";
|
||||
reg = <0x11>;
|
||||
|
||||
AVDD-supply = <®ulator>;
|
||||
DVDD-supply = <®ulator_digital>;
|
||||
|
||||
reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
24
Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
Normal file
24
Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
Normal file
@ -0,0 +1,24 @@
|
||||
* Amlogic Audio PDM input
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-pdm'
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
* "pclk" : peripheral clock.
|
||||
* "dclk" : pdm digital clock
|
||||
* "sysclk" : dsp system clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Example of PDM on the A113 SoC:
|
||||
|
||||
pdm: audio-controller@ff632000 {
|
||||
compatible = "amlogic,axg-pdm";
|
||||
reg = <0x0 0xff632000 0x0 0x34>;
|
||||
#sound-dai-cells = <0>;
|
||||
clocks = <&clkc_audio AUD_CLKID_PDM>,
|
||||
<&clkc_audio AUD_CLKID_PDM_DCLK>,
|
||||
<&clkc_audio AUD_CLKID_PDM_SYSCLK>;
|
||||
clock-names = "pclk", "dclk", "sysclk";
|
||||
};
|
17
Documentation/devicetree/bindings/sound/cs42l51.txt
Normal file
17
Documentation/devicetree/bindings/sound/cs42l51.txt
Normal file
@ -0,0 +1,17 @@
|
||||
CS42L51 audio CODEC
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
||||
clock-names
|
||||
|
||||
- clock-names : must contain "MCLK"
|
||||
|
||||
Example:
|
||||
|
||||
cs42l51: cs42l51@4a {
|
||||
compatible = "cirrus,cs42l51";
|
||||
reg = <0x4a>;
|
||||
clocks = <&mclk_prov>;
|
||||
clock-names = "MCLK";
|
||||
};
|
23
Documentation/devicetree/bindings/sound/maxim,max98088.txt
Normal file
23
Documentation/devicetree/bindings/sound/maxim,max98088.txt
Normal file
@ -0,0 +1,23 @@
|
||||
MAX98088 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "maxim,max98088" or "maxim,max98089".
|
||||
- reg: The I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section
|
||||
"consumer" for more information.
|
||||
- clock-names: must be set to "mclk"
|
||||
|
||||
Example:
|
||||
|
||||
max98089: codec@10 {
|
||||
compatible = "maxim,max98089";
|
||||
reg = <0x10>;
|
||||
clocks = <&clks IMX6QDL_CLK_CKO2>;
|
||||
clock-names = "mclk";
|
||||
};
|
@ -0,0 +1,23 @@
|
||||
Mikroe-PROTO audio board
|
||||
|
||||
Required properties:
|
||||
- compatible: "mikroe,mikroe-proto"
|
||||
- dai-format: Must be "i2s".
|
||||
- i2s-controller: The phandle of the I2S controller.
|
||||
- audio-codec: The phandle of the WM8731 audio codec.
|
||||
Optional properties:
|
||||
- model: The user-visible name of this sound complex.
|
||||
- bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1).
|
||||
- frame-master: Indicates dai-link frame master; for details see simple-card.txt (1).
|
||||
|
||||
(1) : There must be the same master for both bit and frame clocks.
|
||||
|
||||
Example:
|
||||
sound {
|
||||
compatible = "mikroe,mikroe-proto";
|
||||
model = "wm8731 @ sama5d2_xplained";
|
||||
i2s-controller = <&i2s0>;
|
||||
audio-codec = <&wm8731>;
|
||||
dai-format = "i2s";
|
||||
};
|
||||
};
|
16
Documentation/devicetree/bindings/sound/nau8822.txt
Normal file
16
Documentation/devicetree/bindings/sound/nau8822.txt
Normal file
@ -0,0 +1,16 @@
|
||||
NAU8822 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "nuvoton,nau8822"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
codec: nau8822@1a {
|
||||
compatible = "nuvoton,nau8822";
|
||||
reg = <0x1a>;
|
||||
};
|
17
Documentation/devicetree/bindings/sound/pcm3060.txt
Normal file
17
Documentation/devicetree/bindings/sound/pcm3060.txt
Normal file
@ -0,0 +1,17 @@
|
||||
PCM3060 audio CODEC
|
||||
|
||||
This driver supports both I2C and SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm3060"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Examples:
|
||||
|
||||
pcm3060: pcm3060@46 {
|
||||
compatible = "ti,pcm3060";
|
||||
reg = <0x46>;
|
||||
};
|
@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties.
|
||||
Usage: required for mi2s interface
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Must be list of serial data lines used by this dai.
|
||||
should be one or more of the 1-4 sd lines.
|
||||
should be one or more of the 0-3 sd lines.
|
||||
|
||||
- qcom,tdm-sync-mode:
|
||||
Usage: required for tdm interface
|
||||
@ -137,42 +137,42 @@ q6afe@4 {
|
||||
|
||||
prim-mi2s-rx@16 {
|
||||
reg = <16>;
|
||||
qcom,sd-lines = <1 3>;
|
||||
qcom,sd-lines = <0 2>;
|
||||
};
|
||||
|
||||
prim-mi2s-tx@17 {
|
||||
reg = <17>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
|
||||
sec-mi2s-rx@18 {
|
||||
reg = <18>;
|
||||
qcom,sd-lines = <1 4>;
|
||||
qcom,sd-lines = <0 3>;
|
||||
};
|
||||
|
||||
sec-mi2s-tx@19 {
|
||||
reg = <19>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
|
||||
tert-mi2s-rx@20 {
|
||||
reg = <20>;
|
||||
qcom,sd-lines = <2 4>;
|
||||
qcom,sd-lines = <1 3>;
|
||||
};
|
||||
|
||||
tert-mi2s-tx@21 {
|
||||
reg = <21>;
|
||||
qcom,sd-lines = <1>;
|
||||
qcom,sd-lines = <0>;
|
||||
};
|
||||
|
||||
quat-mi2s-rx@22 {
|
||||
reg = <22>;
|
||||
qcom,sd-lines = <1>;
|
||||
qcom,sd-lines = <0>;
|
||||
};
|
||||
|
||||
quat-mi2s-tx@23 {
|
||||
reg = <23>;
|
||||
qcom,sd-lines = <2>;
|
||||
qcom,sd-lines = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -340,10 +340,12 @@ Required properties:
|
||||
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
||||
"renesas,rcar_sound-gen1" if generation1, and
|
||||
"renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
|
||||
"renesas,rcar_sound-gen3" if generation3
|
||||
"renesas,rcar_sound-gen3" if generation3 (or RZ/G2)
|
||||
Examples with soctypes are:
|
||||
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
|
||||
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
|
||||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
@ -353,6 +355,7 @@ Required properties:
|
||||
- "renesas,rcar_sound-r8a7795" (R-Car H3)
|
||||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
||||
- "renesas,rcar_sound-r8a77990" (R-Car E3)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
@ -19,6 +19,10 @@ Required properties:
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks, clock-names: Clock specifier for XTI input clock.
|
||||
If specified, the clock will be enabled when the codec is probed,
|
||||
and disabled when it is removed. The 'clock-names' must be set to 'xti'.
|
||||
|
||||
- st,output-conf: number, Selects the output configuration:
|
||||
0: 2-channel (full-bridge) power, 2-channel data-out
|
||||
1: 2 (half-bridge). 1 (full-bridge) on-board power
|
||||
@ -39,6 +43,9 @@ Optional properties:
|
||||
- st,thermal-warning-recover:
|
||||
If present, thermal warning recovery is enabled.
|
||||
|
||||
- st,fault-detect-recovery:
|
||||
If present, fault detect recovery is enabled.
|
||||
|
||||
- st,thermal-warning-adjustment:
|
||||
If present, thermal warning adjustment is enabled.
|
||||
|
||||
@ -76,6 +83,8 @@ Example:
|
||||
codec: sta32x@38 {
|
||||
compatible = "st,sta32x";
|
||||
reg = <0x1c>;
|
||||
clocks = <&clock>;
|
||||
clock-names = "xti";
|
||||
reset-gpios = <&gpio1 19 0>;
|
||||
power-down-gpios = <&gpio1 16 0>;
|
||||
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
|
||||
|
@ -31,7 +31,11 @@ SAI subnodes required properties:
|
||||
- reg: Base address and size of SAI sub-block register set.
|
||||
- clocks: Must contain one phandle and clock specifier pair
|
||||
for sai_ck which feeds the internal clock generator.
|
||||
If the SAI shares a master clock, with another SAI set as MCLK
|
||||
clock provider, SAI provider phandle must be specified here.
|
||||
- clock-names: Must contain "sai_ck".
|
||||
Must also contain "MCLK", if SAI shares a master clock,
|
||||
with a SAI set as MCLK clock provider.
|
||||
- dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
|
||||
- dma-names: identifier string for each DMA request line
|
||||
"tx": if sai sub-block is configured as playback DAI
|
||||
@ -51,6 +55,9 @@ SAI subnodes Optional properties:
|
||||
configured according to protocol defined in related DAI link node,
|
||||
such as i2s, left justified, right justified, dsp and pdm protocols.
|
||||
Note: ac97 protocol is not supported by SAI driver
|
||||
- #clock-cells: should be 0. This property must be present if the SAI device
|
||||
is a master clock provider, according to clocks bindings, described in
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt.
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
|
@ -10,6 +10,7 @@ Required properties:
|
||||
- "allwinner,sun6i-a31-i2s"
|
||||
- "allwinner,sun8i-a83t-i2s"
|
||||
- "allwinner,sun8i-h3-i2s"
|
||||
- "allwinner,sun50i-a64-codec-i2s"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the I2S interrupt.
|
||||
@ -26,6 +27,7 @@ Required properties for the following compatibles:
|
||||
- "allwinner,sun6i-a31-i2s"
|
||||
- "allwinner,sun8i-a83t-i2s"
|
||||
- "allwinner,sun8i-h3-i2s"
|
||||
- "allwinner,sun50i-a64-codec-i2s"
|
||||
- resets: phandle to the reset line for this codec
|
||||
|
||||
Example:
|
||||
|
@ -0,0 +1,12 @@
|
||||
* Allwinner A64 Codec Analog Controls
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun50i-a64-codec-analog"
|
||||
- reg: must contain the registers location and length
|
||||
|
||||
Example:
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
};
|
@ -14,7 +14,7 @@ Required properties:
|
||||
|
||||
Optional properies:
|
||||
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
|
||||
Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
|
||||
Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage
|
||||
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
|
||||
Default value is "1" (2.2V).
|
||||
|
||||
|
17
Documentation/devicetree/bindings/sound/wm8782.txt
Normal file
17
Documentation/devicetree/bindings/sound/wm8782.txt
Normal file
@ -0,0 +1,17 @@
|
||||
WM8782 stereo ADC
|
||||
|
||||
This device does not have any control interface or reset pins.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8782"
|
||||
- Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V)
|
||||
- Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V)
|
||||
|
||||
Example:
|
||||
|
||||
wm8782: stereo-adc {
|
||||
compatible = "wlf,wm8782";
|
||||
Vdda-supply = <&vdda_supply>;
|
||||
Vdd-supply = <&vdd_supply>;
|
||||
};
|
@ -35,7 +35,6 @@ at,24c08 i2c serial eeprom (24cxx)
|
||||
atmel,at97sc3204t i2c trusted platform module (TPM)
|
||||
capella,cm32181 CM32181: Ambient Light Sensor
|
||||
capella,cm3232 CM3232: Ambient Light Sensor
|
||||
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
|
||||
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
||||
dallas,ds1631 High-Precision Digital Thermometer
|
||||
dallas,ds1672 Dallas DS1672 Real-time Clock
|
||||
|
@ -235,6 +235,7 @@ micrel Micrel Inc.
|
||||
microchip Microchip Technology Inc.
|
||||
microcrystal Micro Crystal AG
|
||||
micron Micron Technology Inc.
|
||||
mikroe MikroElektronika d.o.o.
|
||||
minix MINIX Technology Ltd.
|
||||
miramems MiraMEMS Sensing Technology Co., Ltd.
|
||||
mitsubishi Mitsubishi Electric Corporation
|
||||
|
@ -14619,6 +14619,13 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/ti/netcp*
|
||||
|
||||
TI PCM3060 ASoC CODEC DRIVER
|
||||
M: Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/pcm3060.txt
|
||||
F: sound/soc/codecs/pcm3060*
|
||||
|
||||
TI TAS571X FAMILY ASoC CODEC DRIVER
|
||||
M: Kevin Cernekee <cernekee@chromium.org>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
|
@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
||||
|
||||
#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
|
||||
dai_link->cpu_dai_name)
|
||||
dai_link->cpu_dai_name, NULL)
|
||||
#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
|
||||
dai_link->codec_dai_name)
|
||||
dai_link->codec_dai_name, dai_link->codecs)
|
||||
int asoc_simple_card_parse_clk(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct device_node *dai_of_node,
|
||||
struct asoc_simple_dai *simple_dai,
|
||||
const char *name);
|
||||
const char *dai_name,
|
||||
struct snd_soc_dai_link_component *dlc);
|
||||
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
|
||||
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
|
||||
|
||||
#define asoc_simple_card_parse_cpu(node, dai_link, \
|
||||
list_name, cells_name, is_single_link) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node, \
|
||||
asoc_simple_card_parse_dai(node, NULL, \
|
||||
&dai_link->cpu_of_node, \
|
||||
&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
|
||||
#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name, list_name, cells_name, NULL)
|
||||
asoc_simple_card_parse_dai(node, dai_link->codecs, \
|
||||
&dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name, \
|
||||
list_name, cells_name, NULL)
|
||||
#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \
|
||||
asoc_simple_card_parse_dai(node, &dai_link->platform_of_node, \
|
||||
asoc_simple_card_parse_dai(node, dai_link->platform, \
|
||||
&dai_link->platform_of_node, \
|
||||
NULL, list_name, cells_name, NULL)
|
||||
int asoc_simple_card_parse_dai(struct device_node *node,
|
||||
struct snd_soc_dai_link_component *dlc,
|
||||
struct device_node **endpoint_np,
|
||||
const char **dai_name,
|
||||
const char *list_name,
|
||||
@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node,
|
||||
int *is_single_links);
|
||||
|
||||
#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
|
||||
asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \
|
||||
asoc_simple_card_parse_graph_dai(ep, NULL, \
|
||||
&dai_link->cpu_of_node, \
|
||||
&dai_link->cpu_dai_name)
|
||||
#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
|
||||
asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \
|
||||
asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \
|
||||
&dai_link->codec_of_node, \
|
||||
&dai_link->codec_dai_name)
|
||||
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
|
||||
struct snd_soc_dai_link_component *dlc,
|
||||
struct device_node **endpoint_np,
|
||||
const char **dai_name);
|
||||
|
||||
|
@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
|
||||
|
||||
/*
|
||||
* generic table used for HDA codec-based platforms, possibly with
|
||||
* additional ACPI-enumerated codecs
|
||||
*/
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[];
|
||||
|
||||
#endif
|
||||
|
@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_soc_dai *dai);
|
||||
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
|
||||
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
|
||||
int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
const struct snd_soc_pcm_stream *params,
|
||||
unsigned int num_params,
|
||||
struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
|
||||
@ -590,9 +584,6 @@ struct snd_soc_dapm_widget {
|
||||
void *priv; /* widget specific data */
|
||||
struct regulator *regulator; /* attached regulator */
|
||||
struct pinctrl *pinctrl; /* attached pinctrl */
|
||||
const struct snd_soc_pcm_stream *params; /* params for dai links */
|
||||
unsigned int num_params; /* number of params for dai links */
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
|
||||
/* dapm control */
|
||||
int reg; /* negative reg = no direct dapm */
|
||||
|
@ -103,6 +103,16 @@ struct snd_soc_dpcm_runtime {
|
||||
int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
|
||||
};
|
||||
|
||||
#define for_each_dpcm_fe(be, stream, dpcm) \
|
||||
list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe)
|
||||
|
||||
#define for_each_dpcm_be(fe, stream, dpcm) \
|
||||
list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \
|
||||
list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
#define for_each_dpcm_be_rollback(fe, stream, dpcm) \
|
||||
list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
|
||||
|
||||
/* can this BE stop and free */
|
||||
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
|
||||
struct snd_soc_pcm_runtime *be, int stream);
|
||||
|
@ -372,6 +372,11 @@
|
||||
#define SND_SOC_COMP_ORDER_LATE 1
|
||||
#define SND_SOC_COMP_ORDER_LAST 2
|
||||
|
||||
#define for_each_comp_order(order) \
|
||||
for (order = SND_SOC_COMP_ORDER_FIRST; \
|
||||
order <= SND_SOC_COMP_ORDER_LAST; \
|
||||
order++)
|
||||
|
||||
/*
|
||||
* Bias levels
|
||||
*
|
||||
@ -859,6 +864,11 @@ struct snd_soc_component {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define for_each_component_dais(component, dai)\
|
||||
list_for_each_entry(dai, &(component)->dai_list, list)
|
||||
#define for_each_component_dais_safe(component, dai, _dai)\
|
||||
list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
|
||||
|
||||
struct snd_soc_rtdcom_list {
|
||||
struct snd_soc_component *component;
|
||||
struct list_head list; /* rtd::component_list */
|
||||
@ -915,6 +925,8 @@ struct snd_soc_dai_link {
|
||||
*/
|
||||
const char *platform_name;
|
||||
struct device_node *platform_of_node;
|
||||
struct snd_soc_dai_link_component *platform;
|
||||
|
||||
int id; /* optional ID for machine driver link identification */
|
||||
|
||||
const struct snd_soc_pcm_stream *params;
|
||||
@ -976,6 +988,10 @@ struct snd_soc_dai_link {
|
||||
struct list_head list; /* DAI link list of the soc card */
|
||||
struct snd_soc_dobj dobj; /* For topology */
|
||||
};
|
||||
#define for_each_link_codecs(link, i, codec) \
|
||||
for ((i) = 0; \
|
||||
((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \
|
||||
(i)++)
|
||||
|
||||
struct snd_soc_codec_conf {
|
||||
/*
|
||||
@ -1054,7 +1070,6 @@ struct snd_soc_card {
|
||||
struct snd_soc_dai_link *dai_link; /* predefined links only */
|
||||
int num_links; /* predefined links only */
|
||||
struct list_head dai_link_list; /* all links */
|
||||
int num_dai_links;
|
||||
|
||||
struct list_head rtd_list;
|
||||
int num_rtd;
|
||||
@ -1092,6 +1107,7 @@ struct snd_soc_card {
|
||||
|
||||
/* lists of probed devices belonging to this card */
|
||||
struct list_head component_dev_list;
|
||||
struct list_head list;
|
||||
|
||||
struct list_head widgets;
|
||||
struct list_head paths;
|
||||
@ -1114,6 +1130,23 @@ struct snd_soc_card {
|
||||
|
||||
void *drvdata;
|
||||
};
|
||||
#define for_each_card_prelinks(card, i, link) \
|
||||
for ((i) = 0; \
|
||||
((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \
|
||||
(i)++)
|
||||
|
||||
#define for_each_card_links(card, link) \
|
||||
list_for_each_entry(dai_link, &(card)->dai_link_list, list)
|
||||
#define for_each_card_links_safe(card, link, _link) \
|
||||
list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
|
||||
|
||||
#define for_each_card_rtds(card, rtd) \
|
||||
list_for_each_entry(rtd, &(card)->rtd_list, list)
|
||||
#define for_each_card_rtds_safe(card, rtd, _rtd) \
|
||||
list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list)
|
||||
|
||||
#define for_each_card_components(card, component) \
|
||||
list_for_each_entry(component, &(card)->component_dev_list, card_list)
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
struct snd_soc_pcm_runtime {
|
||||
@ -1124,6 +1157,8 @@ struct snd_soc_pcm_runtime {
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
struct snd_pcm_ops ops;
|
||||
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
|
||||
/* Dynamic PCM BE runtime data */
|
||||
struct snd_soc_dpcm_runtime dpcm[2];
|
||||
int fe_compr;
|
||||
@ -1152,6 +1187,13 @@ struct snd_soc_pcm_runtime {
|
||||
unsigned int dev_registered:1;
|
||||
unsigned int pop_wait:1;
|
||||
};
|
||||
#define for_each_rtd_codec_dai(rtd, i, dai)\
|
||||
for ((i) = 0; \
|
||||
((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
|
||||
(i)++)
|
||||
#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \
|
||||
for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);)
|
||||
|
||||
|
||||
/* mixer control */
|
||||
struct soc_mixer_control {
|
||||
@ -1359,6 +1401,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
|
||||
INIT_LIST_HEAD(&card->dapm_list);
|
||||
INIT_LIST_HEAD(&card->aux_comp_list);
|
||||
INIT_LIST_HEAD(&card->component_dev_list);
|
||||
INIT_LIST_HEAD(&card->list);
|
||||
}
|
||||
|
||||
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
|
||||
|
@ -31,7 +31,6 @@ endif # SND_ARM
|
||||
|
||||
config SND_PXA2XX_LIB
|
||||
tristate
|
||||
select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
|
||||
select SND_DMAENGINE_PCM
|
||||
|
||||
config SND_PXA2XX_LIB_AC97
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/sort.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef __SOUND_HDA_BEEP_H
|
||||
#define __SOUND_HDA_BEEP_H
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
|
||||
#define HDA_BEEP_MODE_OFF 0
|
||||
#define HDA_BEEP_MODE_ON 1
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
/*
|
||||
@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
|
||||
hda_codec_patch_t patch;
|
||||
int err;
|
||||
|
||||
if (codec->bus->core.ext_ops) {
|
||||
if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
|
||||
return -EINVAL;
|
||||
return codec->bus->core.ext_ops->hdev_attach(&codec->core);
|
||||
}
|
||||
|
||||
if (WARN_ON(!codec->preset))
|
||||
return -EINVAL;
|
||||
|
||||
@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
|
||||
if (codec->bus->core.ext_ops) {
|
||||
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
|
||||
return -EINVAL;
|
||||
return codec->bus->core.ext_ops->hdev_detach(&codec->core);
|
||||
}
|
||||
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/initval.h>
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/hda_register.h>
|
||||
|
||||
#define AZX_MAX_CODECS HDA_MAX_CODECS
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <sound/hda_chmap.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
enum eld_versions {
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
@ -63,7 +63,7 @@
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_controller.h"
|
||||
#include "hda_intel.h"
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <linux/module.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
static int dump_coef = -1;
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/export.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_controller.h"
|
||||
|
||||
/* Defines for Nvidia Tegra HDA support */
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -31,8 +31,9 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_i915.h>
|
||||
#include <sound/hda_chmap.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
|
||||
/* si3054 verbs */
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
|
@ -52,7 +52,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/hda_codec.h>
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "../codecs/da7219.h"
|
||||
#include "../codecs/da7219-aad.h"
|
||||
|
||||
#define CZ_PLAT_CLK 25000000
|
||||
#define CZ_PLAT_CLK 48000000
|
||||
#define DUAL_CHANNEL 2
|
||||
|
||||
static struct snd_soc_jack cz_jack;
|
||||
@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
|
||||
da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
|
||||
SND_JACK_HEADSET | SND_JACK_LINEOUT |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||
&cz_jack, NULL, 0);
|
||||
@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static int cz_da7219_startup(struct snd_pcm_substream *substream)
|
||||
static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->play_i2s_instance = I2S_SP_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL1;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
@ -162,11 +183,22 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
|
||||
|
||||
static int cz_max_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->play_i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
@ -177,21 +209,43 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
|
||||
|
||||
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_BT_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_BT_INSTANCE;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
|
||||
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
machine->i2s_instance = I2S_SP_INSTANCE;
|
||||
/*
|
||||
* On this platform for PCM device we support stereo
|
||||
*/
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
machine->cap_i2s_instance = I2S_SP_INSTANCE;
|
||||
machine->capture_channel = CAP_CHANNEL0;
|
||||
return da7219_clk_enable(substream);
|
||||
}
|
||||
@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
|
||||
da7219_clk_disable();
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops cz_da7219_play_ops = {
|
||||
.startup = cz_da7219_play_startup,
|
||||
.shutdown = cz_da7219_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops cz_da7219_cap_ops = {
|
||||
.startup = cz_da7219_startup,
|
||||
.startup = cz_da7219_cap_startup,
|
||||
.shutdown = cz_da7219_shutdown,
|
||||
};
|
||||
|
||||
@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.init = cz_da7219_init,
|
||||
.dpcm_playback = 1,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
.ops = &cz_da7219_play_ops,
|
||||
},
|
||||
{
|
||||
.name = "amd-da7219-cap",
|
||||
|
@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
|
||||
if (pinfo) {
|
||||
rtd->i2s_instance = pinfo->i2s_instance;
|
||||
rtd->capture_channel = pinfo->capture_channel;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
rtd->i2s_instance = pinfo->play_i2s_instance;
|
||||
} else {
|
||||
rtd->i2s_instance = pinfo->cap_i2s_instance;
|
||||
rtd->capture_channel = pinfo->capture_channel;
|
||||
}
|
||||
}
|
||||
if (adata->asic_type == CHIP_STONEY) {
|
||||
val = acp_reg_read(adata->acp_mmio,
|
||||
|
@ -158,7 +158,8 @@ struct audio_drv_data {
|
||||
* and dma driver
|
||||
*/
|
||||
struct acp_platform_info {
|
||||
u16 i2s_instance;
|
||||
u16 play_i2s_instance;
|
||||
u16 cap_i2s_instance;
|
||||
u16 capture_channel;
|
||||
};
|
||||
|
||||
|
@ -97,4 +97,16 @@ config SND_ATMEL_SOC_I2S
|
||||
help
|
||||
Say Y or M if you want to add support for Atmel ASoc driver for boards
|
||||
using I2S.
|
||||
|
||||
config SND_SOC_MIKROE_PROTO
|
||||
tristate "Support for Mikroe-PROTO board"
|
||||
depends on OF
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8731
|
||||
help
|
||||
Say Y or M if you want to add support for MikroElektronika PROTO Audio
|
||||
Board. This board contains the WM8731 codec, which can be configured
|
||||
using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
|
||||
Both playback and capture are supported.
|
||||
|
||||
endif
|
||||
|
@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
||||
snd-atmel-soc-classd-objs := atmel-classd.o
|
||||
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
|
||||
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
|
||||
snd-soc-mikroe-proto-objs := mikroe-proto.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
|
||||
@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
|
||||
obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o
|
||||
|
@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev)
|
||||
struct ssc_device *ssc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_register_component(dev, &atmel_ssc_component,
|
||||
ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,
|
||||
&atmel_ssc_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register DAI: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ssc->pdata->use_dma)
|
||||
@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register PCM: %d\n", ret);
|
||||
goto err_unregister_dai;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_dai:
|
||||
snd_soc_unregister_component(dev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asoc_ssc_exit(struct device *dev)
|
||||
@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev)
|
||||
atmel_pcm_dma_platform_unregister(dev);
|
||||
else
|
||||
atmel_pcm_pdc_platform_unregister(dev);
|
||||
|
||||
snd_soc_unregister_component(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
165
sound/soc/atmel/mikroe-proto.c
Normal file
165
sound/soc/atmel/mikroe-proto.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* ASoC driver for PROTO AudioCODEC (with a WM8731)
|
||||
*
|
||||
* Author: Florian Meier, <koalo@koalo.de>
|
||||
* Copyright 2013
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "../codecs/wm8731.h"
|
||||
|
||||
#define XTAL_RATE 12288000 /* This is fixed on this board */
|
||||
|
||||
static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
/* Set proto sysclk */
|
||||
int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
XTAL_RATE, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget snd_proto_widget[] = {
|
||||
SND_SOC_DAPM_MIC("Microphone Jack", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route snd_proto_route[] = {
|
||||
/* speaker connected to LHPOUT/RHPOUT */
|
||||
{"Headphone Jack", NULL, "LHPOUT"},
|
||||
{"Headphone Jack", NULL, "RHPOUT"},
|
||||
|
||||
/* mic is connected to Mic Jack, with WM8731 Mic Bias */
|
||||
{"MICIN", NULL, "Mic Bias"},
|
||||
{"Mic Bias", NULL, "Microphone Jack"},
|
||||
};
|
||||
|
||||
/* audio machine driver */
|
||||
static struct snd_soc_card snd_proto = {
|
||||
.name = "snd_mikroe_proto",
|
||||
.owner = THIS_MODULE,
|
||||
.dapm_widgets = snd_proto_widget,
|
||||
.num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),
|
||||
.dapm_routes = snd_proto_route,
|
||||
.num_dapm_routes = ARRAY_SIZE(snd_proto_route),
|
||||
};
|
||||
|
||||
static int snd_proto_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct device_node *bitclkmaster = NULL;
|
||||
struct device_node *framemaster = NULL;
|
||||
unsigned int dai_fmt;
|
||||
int ret = 0;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "No device node supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_proto.dev = &pdev->dev;
|
||||
ret = snd_soc_of_parse_card_name(&snd_proto, "model");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_proto.dai_link = dai;
|
||||
snd_proto.num_links = 1;
|
||||
|
||||
dai->name = "WM8731";
|
||||
dai->stream_name = "WM8731 HiFi";
|
||||
dai->codec_dai_name = "wm8731-hifi";
|
||||
dai->init = &snd_proto_init;
|
||||
|
||||
codec_np = of_parse_phandle(np, "audio-codec", 0);
|
||||
if (!codec_np) {
|
||||
dev_err(&pdev->dev, "audio-codec node missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dai->codec_of_node = codec_np;
|
||||
|
||||
cpu_np = of_parse_phandle(np, "i2s-controller", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "i2s-controller missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dai->cpu_of_node = cpu_np;
|
||||
dai->platform_of_node = cpu_np;
|
||||
|
||||
dai_fmt = snd_soc_of_parse_daifmt(np, NULL,
|
||||
&bitclkmaster, &framemaster);
|
||||
if (bitclkmaster != framemaster) {
|
||||
dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bitclkmaster) {
|
||||
dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
|
||||
if (codec_np == bitclkmaster)
|
||||
dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
|
||||
else
|
||||
dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
|
||||
}
|
||||
of_node_put(bitclkmaster);
|
||||
of_node_put(framemaster);
|
||||
dai->dai_fmt = dai_fmt;
|
||||
|
||||
of_node_put(codec_np);
|
||||
of_node_put(cpu_np);
|
||||
|
||||
ret = snd_soc_register_card(&snd_proto);
|
||||
if (ret && ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_card() failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int snd_proto_remove(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_unregister_card(&snd_proto);
|
||||
}
|
||||
|
||||
static const struct of_device_id snd_proto_of_match[] = {
|
||||
{ .compatible = "mikroe,mikroe-proto", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, snd_proto_of_match);
|
||||
|
||||
static struct platform_driver snd_proto_driver = {
|
||||
.driver = {
|
||||
.name = "snd-mikroe-proto",
|
||||
.of_match_table = snd_proto_of_match,
|
||||
},
|
||||
.probe = snd_proto_probe,
|
||||
.remove = snd_proto_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(snd_proto_driver);
|
||||
|
||||
MODULE_AUTHOR("Florian Meier");
|
||||
MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,44 +1,38 @@
|
||||
/*
|
||||
* TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
|
||||
*
|
||||
* Copyright (C) 2016 Axentia Technologies AB
|
||||
*
|
||||
* Author: Peter Rosin <peda@axentia.se>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* loop1 relays
|
||||
* IN1 +---o +------------+ o---+ OUT1
|
||||
* \ /
|
||||
* + +
|
||||
* | / |
|
||||
* +--o +--. |
|
||||
* | add | |
|
||||
* | V |
|
||||
* | .---. |
|
||||
* DAC +----------->|Sum|---+
|
||||
* | '---' |
|
||||
* | |
|
||||
* + +
|
||||
*
|
||||
* IN2 +---o--+------------+--o---+ OUT2
|
||||
* loop2 relays
|
||||
*
|
||||
* The 'loop1' gpio pin controlls two relays, which are either in loop
|
||||
* position, meaning that input and output are directly connected, or
|
||||
* they are in mixer position, meaning that the signal is passed through
|
||||
* the 'Sum' mixer. Similarly for 'loop2'.
|
||||
*
|
||||
* In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
|
||||
* mixer (if 'add' is active) and feeding the mixer output to OUT1. The
|
||||
* 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
|
||||
* IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
|
||||
* of the (filtered) output from the PCM5142 codec.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
|
||||
//
|
||||
// Copyright (C) 2016 Axentia Technologies AB
|
||||
//
|
||||
// Author: Peter Rosin <peda@axentia.se>
|
||||
//
|
||||
// loop1 relays
|
||||
// IN1 +---o +------------+ o---+ OUT1
|
||||
// \ /
|
||||
// + +
|
||||
// | / |
|
||||
// +--o +--. |
|
||||
// | add | |
|
||||
// | V |
|
||||
// | .---. |
|
||||
// DAC +----------->|Sum|---+
|
||||
// | '---' |
|
||||
// | |
|
||||
// + +
|
||||
//
|
||||
// IN2 +---o--+------------+--o---+ OUT2
|
||||
// loop2 relays
|
||||
//
|
||||
// The 'loop1' gpio pin controlls two relays, which are either in loop
|
||||
// position, meaning that input and output are directly connected, or
|
||||
// they are in mixer position, meaning that the signal is passed through
|
||||
// the 'Sum' mixer. Similarly for 'loop2'.
|
||||
//
|
||||
// In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
|
||||
// mixer (if 'add' is active) and feeding the mixer output to OUT1. The
|
||||
// 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
|
||||
// IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
|
||||
// of the (filtered) output from the PCM5142 codec.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -452,4 +446,4 @@ module_platform_driver(tse850_driver);
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
|
||||
MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1334,7 +1334,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
|
||||
cygaud->active_ports = 0;
|
||||
|
||||
dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
|
||||
err = snd_soc_register_component(dev, &cygnus_ssp_component,
|
||||
err = devm_snd_soc_register_component(dev, &cygnus_ssp_component,
|
||||
cygnus_ssp_dai, active_port_count);
|
||||
if (err) {
|
||||
dev_err(dev, "snd_soc_register_dai failed\n");
|
||||
@ -1345,32 +1345,27 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
|
||||
if (cygaud->irq_num <= 0) {
|
||||
dev_err(dev, "platform_get_irq failed\n");
|
||||
err = cygaud->irq_num;
|
||||
goto err_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = audio_clk_init(pdev, cygaud);
|
||||
if (err) {
|
||||
dev_err(dev, "audio clock initialization failed\n");
|
||||
goto err_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = cygnus_soc_platform_register(dev, cygaud);
|
||||
if (err) {
|
||||
dev_err(dev, "platform reg error %d\n", err);
|
||||
goto err_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
snd_soc_unregister_component(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cygnus_ssp_remove(struct platform_device *pdev)
|
||||
{
|
||||
cygnus_soc_platform_unregister(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_ES7241
|
||||
select SND_SOC_GTM601
|
||||
select SND_SOC_HDAC_HDMI
|
||||
select SND_SOC_HDAC_HDA
|
||||
select SND_SOC_ICS43432
|
||||
select SND_SOC_INNO_RK3036
|
||||
select SND_SOC_ISABELLE if I2C
|
||||
@ -109,6 +110,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_MT6351 if MTK_PMIC_WRAP
|
||||
select SND_SOC_NAU8540 if I2C
|
||||
select SND_SOC_NAU8810 if I2C
|
||||
select SND_SOC_NAU8822 if I2C
|
||||
select SND_SOC_NAU8824 if I2C
|
||||
select SND_SOC_NAU8825 if I2C
|
||||
select SND_SOC_HDMI_CODEC
|
||||
@ -119,6 +121,8 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_PCM186X_I2C if I2C
|
||||
select SND_SOC_PCM186X_SPI if SPI_MASTER
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_PCM3060_I2C if I2C
|
||||
select SND_SOC_PCM3060_SPI if SPI_MASTER
|
||||
select SND_SOC_PCM3168A_I2C if I2C
|
||||
select SND_SOC_PCM3168A_SPI if SPI_MASTER
|
||||
select SND_SOC_PCM5102A
|
||||
@ -575,7 +579,11 @@ config SND_SOC_DA9055
|
||||
tristate
|
||||
|
||||
config SND_SOC_DMIC
|
||||
tristate
|
||||
tristate "Generic Digital Microphone CODEC"
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Enable support for the Generic Digital Microphone CODEC.
|
||||
Select this if your sound card has DMICs.
|
||||
|
||||
config SND_SOC_HDMI_CODEC
|
||||
tristate
|
||||
@ -615,6 +623,10 @@ config SND_SOC_HDAC_HDMI
|
||||
select SND_PCM_ELD
|
||||
select HDMI
|
||||
|
||||
config SND_SOC_HDAC_HDA
|
||||
tristate
|
||||
select SND_HDA
|
||||
|
||||
config SND_SOC_ICS43432
|
||||
tristate
|
||||
|
||||
@ -629,7 +641,8 @@ config SND_SOC_LM49453
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98088
|
||||
tristate
|
||||
tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_MAX98090
|
||||
tristate
|
||||
@ -732,6 +745,21 @@ config SND_SOC_PCM186X_SPI
|
||||
config SND_SOC_PCM3008
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM3060
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM3060_I2C
|
||||
tristate "Texas Instruments PCM3060 CODEC - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_PCM3060
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_PCM3060_SPI
|
||||
tristate "Texas Instruments PCM3060 CODEC - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_PCM3060
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_PCM3168A
|
||||
tristate
|
||||
|
||||
@ -1299,6 +1327,10 @@ config SND_SOC_NAU8810
|
||||
tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_NAU8822
|
||||
tristate "Nuvoton Technology Corporation NAU88C22 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_NAU8824
|
||||
tristate "Nuvoton Technology Corporation NAU88L24 CODEC"
|
||||
depends on I2C
|
||||
|
@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
|
||||
snd-soc-es8328-spi-objs := es8328-spi.o
|
||||
snd-soc-gtm601-objs := gtm601.o
|
||||
snd-soc-hdac-hdmi-objs := hdac_hdmi.o
|
||||
snd-soc-hdac-hda-objs := hdac_hda.o
|
||||
snd-soc-ics43432-objs := ics43432.o
|
||||
snd-soc-inno-rk3036-objs := inno_rk3036.o
|
||||
snd-soc-isabelle-objs := isabelle.o
|
||||
@ -106,6 +107,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
|
||||
snd-soc-mt6351-objs := mt6351.o
|
||||
snd-soc-nau8540-objs := nau8540.o
|
||||
snd-soc-nau8810-objs := nau8810.o
|
||||
snd-soc-nau8822-objs := nau8822.o
|
||||
snd-soc-nau8824-objs := nau8824.o
|
||||
snd-soc-nau8825-objs := nau8825.o
|
||||
snd-soc-hdmi-codec-objs := hdmi-codec.o
|
||||
@ -119,6 +121,9 @@ snd-soc-pcm186x-objs := pcm186x.o
|
||||
snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
|
||||
snd-soc-pcm186x-spi-objs := pcm186x-spi.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-pcm3060-objs := pcm3060.o
|
||||
snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o
|
||||
snd-soc-pcm3060-spi-objs := pcm3060-spi.o
|
||||
snd-soc-pcm3168a-objs := pcm3168a.o
|
||||
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
|
||||
snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
|
||||
@ -338,6 +343,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
|
||||
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
|
||||
obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
|
||||
obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
|
||||
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
|
||||
obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
|
||||
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
|
||||
@ -366,6 +372,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
|
||||
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
|
||||
@ -379,6 +386,9 @@ obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o
|
||||
obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3060) += snd-soc-pcm3060.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3060_I2C) += snd-soc-pcm3060-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3060_SPI) += snd-soc-pcm3060-spi.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o
|
||||
|
@ -518,7 +518,8 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
|
||||
ARRAY_SIZE(adau1761_jack_detect_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
|
||||
/* fall through */
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE:
|
||||
ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
|
||||
ARRAY_SIZE(adau1761_no_dmic_routes));
|
||||
if (ret)
|
||||
|
@ -21,11 +21,18 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau17x1.h"
|
||||
#include "adau-utils.h"
|
||||
|
||||
#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006
|
||||
#define ADAU17X1_SAFELOAD_TRIGGER 0x0007
|
||||
#define ADAU17X1_SAFELOAD_DATA 0x0001
|
||||
#define ADAU17X1_SAFELOAD_DATA_SIZE 20
|
||||
#define ADAU17X1_WORD_SIZE 4
|
||||
|
||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
||||
};
|
||||
@ -60,6 +67,9 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
|
||||
SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
|
||||
};
|
||||
|
||||
static int adau17x1_setup_firmware(struct snd_soc_component *component,
|
||||
unsigned int rate);
|
||||
|
||||
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
@ -313,7 +323,7 @@ static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
|
||||
{ "Capture", NULL, "Right Decimator" },
|
||||
};
|
||||
|
||||
bool adau17x1_has_dsp(struct adau *adau)
|
||||
static bool adau17x1_has_dsp(struct adau *adau)
|
||||
{
|
||||
switch (adau->type) {
|
||||
case ADAU1761:
|
||||
@ -324,7 +334,17 @@ bool adau17x1_has_dsp(struct adau *adau)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
|
||||
|
||||
static bool adau17x1_has_safeload(struct adau *adau)
|
||||
{
|
||||
switch (adau->type) {
|
||||
case ADAU1761:
|
||||
case ADAU1781:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
@ -836,7 +856,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
|
||||
|
||||
int adau17x1_setup_firmware(struct snd_soc_component *component,
|
||||
static int adau17x1_setup_firmware(struct snd_soc_component *component,
|
||||
unsigned int rate)
|
||||
{
|
||||
int ret;
|
||||
@ -880,7 +900,6 @@ err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_component *component)
|
||||
{
|
||||
@ -957,6 +976,56 @@ int adau17x1_resume(struct snd_soc_component *component)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_resume);
|
||||
|
||||
static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
|
||||
const uint8_t bytes[], size_t len)
|
||||
{
|
||||
uint8_t buf[ADAU17X1_WORD_SIZE];
|
||||
uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE];
|
||||
unsigned int addr_offset;
|
||||
unsigned int nbr_words;
|
||||
int ret;
|
||||
|
||||
/* write data to safeload addresses. Check if len is not a multiple of
|
||||
* 4 bytes, if so we need to zero pad.
|
||||
*/
|
||||
nbr_words = len / ADAU17X1_WORD_SIZE;
|
||||
if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) {
|
||||
ret = regmap_raw_write(sigmadsp->control_data,
|
||||
ADAU17X1_SAFELOAD_DATA, bytes, len);
|
||||
} else {
|
||||
nbr_words++;
|
||||
memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE);
|
||||
memcpy(data, bytes, len);
|
||||
ret = regmap_raw_write(sigmadsp->control_data,
|
||||
ADAU17X1_SAFELOAD_DATA, data,
|
||||
nbr_words * ADAU17X1_WORD_SIZE);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Write target address, target address is offset by 1 */
|
||||
addr_offset = addr - 1;
|
||||
put_unaligned_be32(addr_offset, buf);
|
||||
ret = regmap_raw_write(sigmadsp->control_data,
|
||||
ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* write nbr of words to trigger address */
|
||||
put_unaligned_be32(nbr_words, buf);
|
||||
ret = regmap_raw_write(sigmadsp->control_data,
|
||||
ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sigmadsp_ops adau17x1_sigmadsp_ops = {
|
||||
.safeload = adau17x1_safeload,
|
||||
};
|
||||
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||
const char *firmware_name)
|
||||
@ -1002,8 +1071,13 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
dev_set_drvdata(dev, adau);
|
||||
|
||||
if (firmware_name) {
|
||||
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
|
||||
firmware_name);
|
||||
if (adau17x1_has_safeload(adau)) {
|
||||
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
|
||||
&adau17x1_sigmadsp_ops, firmware_name);
|
||||
} else {
|
||||
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
|
||||
NULL, firmware_name);
|
||||
}
|
||||
if (IS_ERR(adau->sigmadsp)) {
|
||||
dev_warn(dev, "Could not find firmware file: %ld\n",
|
||||
PTR_ERR(adau->sigmadsp));
|
||||
|
@ -68,10 +68,6 @@ int adau17x1_resume(struct snd_soc_component *component);
|
||||
|
||||
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
|
||||
|
||||
int adau17x1_setup_firmware(struct snd_soc_component *component,
|
||||
unsigned int rate);
|
||||
bool adau17x1_has_dsp(struct adau *adau);
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL 0x4000
|
||||
#define ADAU17X1_PLL_CONTROL 0x4002
|
||||
#define ADAU17X1_REC_POWER_MGMT 0x4009
|
||||
|
@ -154,11 +154,11 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = {
|
||||
SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
|
||||
6, 1, 0),
|
||||
SOC_ENUM("C Data Access", cam_mode_enum),
|
||||
SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1),
|
||||
SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
|
||||
3, 1, 0),
|
||||
SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
|
||||
SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
|
||||
0, 1, 0),
|
||||
SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0),
|
||||
SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
|
||||
SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
|
||||
};
|
||||
@ -221,10 +221,11 @@ static const struct snd_soc_dapm_route cs4265_audio_map[] = {
|
||||
{"LINEOUTR", NULL, "DAC"},
|
||||
{"SPDIFOUT", NULL, "SPDIF"},
|
||||
|
||||
{"Pre-amp MIC", NULL, "MICL"},
|
||||
{"Pre-amp MIC", NULL, "MICR"},
|
||||
{"ADC Mux", "MIC", "Pre-amp MIC"},
|
||||
{"ADC Mux", "LINEIN", "LINEINL"},
|
||||
{"ADC Mux", "LINEIN", "LINEINR"},
|
||||
{"ADC Mux", "MIC", "MICL"},
|
||||
{"ADC Mux", "MIC", "MICR"},
|
||||
{"ADC", NULL, "ADC Mux"},
|
||||
{"DOUT", NULL, "ADC"},
|
||||
{"DAI1 Capture", NULL, "DOUT"},
|
||||
@ -496,7 +497,8 @@ static int cs4265_set_bias_level(struct snd_soc_component *component,
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops cs4265_ops = {
|
||||
.hw_params = cs4265_pcm_hw_params,
|
||||
|
@ -21,6 +21,7 @@
|
||||
* - master mode *NOT* supported
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@ -41,6 +42,7 @@ enum master_slave_mode {
|
||||
|
||||
struct cs42l51_private {
|
||||
unsigned int mclk;
|
||||
struct clk *mclk_handle;
|
||||
unsigned int audio_mode; /* The mode (I2S or left-justified) */
|
||||
enum master_slave_mode func;
|
||||
};
|
||||
@ -237,6 +239,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
|
||||
&cs42l51_adcr_mux_controls),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = {
|
||||
SND_SOC_DAPM_CLOCK_SUPPLY("MCLK")
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs42l51_routes[] = {
|
||||
{"HPL", NULL, "Left DAC"},
|
||||
{"HPR", NULL, "Right DAC"},
|
||||
@ -487,6 +493,14 @@ static struct snd_soc_dai_driver cs42l51_dai = {
|
||||
static int cs42l51_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
int ret, reg;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
struct cs42l51_private *cs42l51;
|
||||
|
||||
cs42l51 = snd_soc_component_get_drvdata(component);
|
||||
dapm = snd_soc_component_get_dapm(component);
|
||||
|
||||
if (cs42l51->mclk_handle)
|
||||
snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1);
|
||||
|
||||
/*
|
||||
* DAC configuration
|
||||
@ -540,6 +554,13 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
|
||||
|
||||
dev_set_drvdata(dev, cs42l51);
|
||||
|
||||
cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
|
||||
if (IS_ERR(cs42l51->mclk_handle)) {
|
||||
if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT)
|
||||
return PTR_ERR(cs42l51->mclk_handle);
|
||||
cs42l51->mclk_handle = NULL;
|
||||
}
|
||||
|
||||
/* Verify that we have a CS42L51 */
|
||||
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
|
||||
if (ret < 0) {
|
||||
|
@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = {
|
||||
{.compatible = "dmic-codec"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dmic_dev_match);
|
||||
|
||||
static struct platform_driver dmic_driver = {
|
||||
.driver = {
|
||||
|
@ -566,14 +566,14 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
|
||||
break;
|
||||
case 22579200:
|
||||
mclkdiv2 = 1;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case 11289600:
|
||||
es8328->sysclk_constraints = &constraints_11289;
|
||||
es8328->mclk_ratios = ratios_11289;
|
||||
break;
|
||||
case 24576000:
|
||||
mclkdiv2 = 1;
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
case 12288000:
|
||||
es8328->sysclk_constraints = &constraints_12288;
|
||||
es8328->mclk_ratios = ratios_12288;
|
||||
|
483
sound/soc/codecs/hdac_hda.c
Normal file
483
sound/soc/codecs/hdac_hda.c
Normal file
@ -0,0 +1,483 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright(c) 2015-18 Intel Corporation.
|
||||
|
||||
/*
|
||||
* hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers
|
||||
* with ASoC platform drivers. These APIs are called by the legacy HDA
|
||||
* codec drivers using hdac_ext_bus_ops ops.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/hda_codec.h>
|
||||
#include <sound/hda_register.h>
|
||||
#include "hdac_hda.h"
|
||||
|
||||
#define HDAC_ANALOG_DAI_ID 0
|
||||
#define HDAC_DIGITAL_DAI_ID 1
|
||||
#define HDAC_ALT_ANALOG_DAI_ID 2
|
||||
|
||||
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
|
||||
SNDRV_PCM_FMTBIT_U8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_U16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_U24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | \
|
||||
SNDRV_PCM_FMTBIT_U32_LE | \
|
||||
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
|
||||
|
||||
static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width);
|
||||
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
static struct snd_soc_dai_ops hdac_hda_dai_ops = {
|
||||
.startup = hdac_hda_dai_open,
|
||||
.shutdown = hdac_hda_dai_close,
|
||||
.prepare = hdac_hda_dai_prepare,
|
||||
.hw_free = hdac_hda_dai_hw_free,
|
||||
.set_tdm_slot = hdac_hda_dai_set_tdm_slot,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver hdac_hda_dais[] = {
|
||||
{
|
||||
.id = HDAC_ANALOG_DAI_ID,
|
||||
.name = "Analog Codec DAI",
|
||||
.ops = &hdac_hda_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "Analog Codec Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Analog Codec Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = HDAC_DIGITAL_DAI_ID,
|
||||
.name = "Digital Codec DAI",
|
||||
.ops = &hdac_hda_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "Digital Codec Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Digital Codec Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = HDAC_ALT_ANALOG_DAI_ID,
|
||||
.name = "Alt Analog Codec DAI",
|
||||
.ops = &hdac_hda_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "Alt Analog Codec Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Alt Analog Codec Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = STUB_FORMATS,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct hdac_hda_pcm *pcm;
|
||||
|
||||
hda_pvt = snd_soc_component_get_drvdata(component);
|
||||
pcm = &hda_pvt->pcm[dai->id];
|
||||
if (tx_mask)
|
||||
pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
|
||||
else
|
||||
pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct hda_pcm_stream *hda_stream;
|
||||
struct hda_pcm *pcm;
|
||||
|
||||
hda_pvt = snd_soc_component_get_drvdata(component);
|
||||
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
|
||||
if (!pcm)
|
||||
return -EINVAL;
|
||||
|
||||
hda_stream = &pcm->stream[substream->stream];
|
||||
snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct hdac_device *hdev;
|
||||
struct hda_pcm_stream *hda_stream;
|
||||
unsigned int format_val;
|
||||
struct hda_pcm *pcm;
|
||||
unsigned int stream;
|
||||
int ret = 0;
|
||||
|
||||
hda_pvt = snd_soc_component_get_drvdata(component);
|
||||
hdev = &hda_pvt->codec.core;
|
||||
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
|
||||
if (!pcm)
|
||||
return -EINVAL;
|
||||
|
||||
hda_stream = &pcm->stream[substream->stream];
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
hda_stream->maxbps,
|
||||
0);
|
||||
if (!format_val) {
|
||||
dev_err(&hdev->dev,
|
||||
"invalid format_val, rate=%d, ch=%d, format=%d\n",
|
||||
runtime->rate, runtime->channels, runtime->format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream];
|
||||
|
||||
ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream,
|
||||
stream, format_val, substream);
|
||||
if (ret < 0)
|
||||
dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct hda_pcm_stream *hda_stream;
|
||||
struct hda_pcm *pcm;
|
||||
int ret;
|
||||
|
||||
hda_pvt = snd_soc_component_get_drvdata(component);
|
||||
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
|
||||
if (!pcm)
|
||||
return -EINVAL;
|
||||
|
||||
snd_hda_codec_pcm_get(pcm);
|
||||
|
||||
hda_stream = &pcm->stream[substream->stream];
|
||||
|
||||
ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream);
|
||||
if (ret < 0)
|
||||
snd_hda_codec_pcm_put(pcm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct hda_pcm_stream *hda_stream;
|
||||
struct hda_pcm *pcm;
|
||||
|
||||
hda_pvt = snd_soc_component_get_drvdata(component);
|
||||
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
|
||||
if (!pcm)
|
||||
return;
|
||||
|
||||
hda_stream = &pcm->stream[substream->stream];
|
||||
|
||||
hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream);
|
||||
|
||||
snd_hda_codec_pcm_put(pcm);
|
||||
}
|
||||
|
||||
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hda_codec *hcodec = &hda_pvt->codec;
|
||||
struct hda_pcm *cpcm;
|
||||
const char *pcm_name;
|
||||
|
||||
switch (dai->id) {
|
||||
case HDAC_ANALOG_DAI_ID:
|
||||
pcm_name = "Analog";
|
||||
break;
|
||||
case HDAC_DIGITAL_DAI_ID:
|
||||
pcm_name = "Digital";
|
||||
break;
|
||||
case HDAC_ALT_ANALOG_DAI_ID:
|
||||
pcm_name = "Alt Analog";
|
||||
break;
|
||||
default:
|
||||
dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
|
||||
if (strpbrk(cpcm->name, pcm_name))
|
||||
return cpcm;
|
||||
}
|
||||
|
||||
dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int hdac_hda_codec_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct hdac_hda_priv *hda_pvt =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_component_get_dapm(component);
|
||||
struct hdac_device *hdev = &hda_pvt->codec.core;
|
||||
struct hda_codec *hcodec = &hda_pvt->codec;
|
||||
struct hdac_ext_link *hlink;
|
||||
hda_codec_patch_t patch;
|
||||
int ret;
|
||||
|
||||
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
|
||||
if (!hlink) {
|
||||
dev_err(&hdev->dev, "hdac link not found\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
|
||||
|
||||
ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
|
||||
hdev->addr, hcodec);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
|
||||
goto error_no_pm;
|
||||
}
|
||||
|
||||
/*
|
||||
* snd_hda_codec_device_new decrements the usage count so call get pm
|
||||
* else the device will be powered off
|
||||
*/
|
||||
pm_runtime_get_noresume(&hdev->dev);
|
||||
|
||||
hcodec->bus->card = dapm->card->snd_card;
|
||||
|
||||
ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = snd_hdac_regmap_init(&hcodec->core);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "regmap init failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
patch = (hda_codec_patch_t)hcodec->preset->driver_data;
|
||||
if (patch) {
|
||||
ret = patch(hcodec);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "patch failed %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
dev_dbg(&hdev->dev, "no patch file found\n");
|
||||
}
|
||||
|
||||
ret = snd_hda_codec_parse_pcms(hcodec);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = snd_hda_codec_build_controls(hcodec);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "unable to create controls %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hcodec->core.lazy_cache = true;
|
||||
|
||||
/*
|
||||
* hdac_device core already sets the state to active and calls
|
||||
* get_noresume. So enable runtime and set the device to suspend.
|
||||
* pm_runtime_enable is also called during codec registeration
|
||||
*/
|
||||
pm_runtime_put(&hdev->dev);
|
||||
pm_runtime_suspend(&hdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pm_runtime_put(&hdev->dev);
|
||||
error_no_pm:
|
||||
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hdac_hda_codec_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct hdac_hda_priv *hda_pvt =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
struct hdac_device *hdev = &hda_pvt->codec.core;
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
|
||||
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
|
||||
if (!hlink) {
|
||||
dev_err(&hdev->dev, "hdac link not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
|
||||
pm_runtime_disable(&hdev->dev);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
|
||||
{"AIF1TX", NULL, "Codec Input Pin1"},
|
||||
{"AIF2TX", NULL, "Codec Input Pin2"},
|
||||
{"AIF3TX", NULL, "Codec Input Pin3"},
|
||||
|
||||
{"Codec Output Pin1", NULL, "AIF1RX"},
|
||||
{"Codec Output Pin2", NULL, "AIF2RX"},
|
||||
{"Codec Output Pin3", NULL, "AIF3RX"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = {
|
||||
/* Audio Interface */
|
||||
SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0,
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
|
||||
/* Input Pins */
|
||||
SND_SOC_DAPM_INPUT("Codec Input Pin1"),
|
||||
SND_SOC_DAPM_INPUT("Codec Input Pin2"),
|
||||
SND_SOC_DAPM_INPUT("Codec Input Pin3"),
|
||||
|
||||
/* Output Pins */
|
||||
SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
|
||||
SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
|
||||
SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver hdac_hda_codec = {
|
||||
.probe = hdac_hda_codec_probe,
|
||||
.remove = hdac_hda_codec_remove,
|
||||
.idle_bias_on = false,
|
||||
.dapm_widgets = hdac_hda_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets),
|
||||
.dapm_routes = hdac_hda_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes),
|
||||
};
|
||||
|
||||
static int hdac_hda_dev_probe(struct hdac_device *hdev)
|
||||
{
|
||||
struct hdac_ext_link *hlink;
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
int ret;
|
||||
|
||||
/* hold the ref while we probe */
|
||||
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
|
||||
if (!hlink) {
|
||||
dev_err(&hdev->dev, "hdac link not found\n");
|
||||
return -EIO;
|
||||
}
|
||||
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
|
||||
|
||||
hda_pvt = hdac_to_hda_priv(hdev);
|
||||
if (!hda_pvt)
|
||||
return -ENOMEM;
|
||||
|
||||
/* ASoC specific initialization */
|
||||
ret = devm_snd_soc_register_component(&hdev->dev,
|
||||
&hdac_hda_codec, hdac_hda_dais,
|
||||
ARRAY_SIZE(hdac_hda_dais));
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&hdev->dev, hda_pvt);
|
||||
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdac_hda_dev_remove(struct hdac_device *hdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hdac_ext_bus_ops hdac_ops = {
|
||||
.hdev_attach = hdac_hda_dev_probe,
|
||||
.hdev_detach = hdac_hda_dev_remove,
|
||||
};
|
||||
|
||||
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void)
|
||||
{
|
||||
return &hdac_ops;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers");
|
||||
MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>");
|
24
sound/soc/codecs/hdac_hda.h
Normal file
24
sound/soc/codecs/hdac_hda.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright(c) 2015-18 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef __HDAC_HDA_H__
|
||||
#define __HDAC_HDA_H__
|
||||
|
||||
struct hdac_hda_pcm {
|
||||
int stream_tag[2];
|
||||
};
|
||||
|
||||
struct hdac_hda_priv {
|
||||
struct hda_codec codec;
|
||||
struct hdac_hda_pcm pcm[2];
|
||||
};
|
||||
|
||||
#define hdac_to_hda_priv(_hdac) \
|
||||
container_of(_hdac, struct hdac_hda_priv, codec.core)
|
||||
#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core)
|
||||
|
||||
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void);
|
||||
|
||||
#endif /* __HDAC_HDA_H__ */
|
@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Filter out 44.1, 88.2 and 176.4Khz */
|
||||
rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_176400);
|
||||
if (!rates)
|
||||
return -EINVAL;
|
||||
|
||||
sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
|
||||
hdmi_dais[i].name = devm_kstrdup(&hdev->dev,
|
||||
dai_name, GFP_KERNEL);
|
||||
@ -1598,7 +1604,7 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
list_for_each_entry(rtd, &card->rtd_list, list) {
|
||||
for_each_card_rtds(card, rtd) {
|
||||
if (rtd->pcm && (rtd->pcm->device == device))
|
||||
return rtd->pcm;
|
||||
}
|
||||
@ -1961,9 +1967,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
|
||||
|
||||
port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
|
||||
|
||||
if (!port)
|
||||
return 0;
|
||||
|
||||
if (!port || !port->eld.eld_valid)
|
||||
return 0;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -42,6 +43,7 @@ struct max98088_priv {
|
||||
struct regmap *regmap;
|
||||
enum max98088_type devtype;
|
||||
struct max98088_pdata *pdata;
|
||||
struct clk *mclk;
|
||||
unsigned int sysclk;
|
||||
struct max98088_cdata dai[2];
|
||||
int eq_textcnt;
|
||||
@ -1103,6 +1105,11 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
if (freq == max98088->sysclk)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR(max98088->mclk)) {
|
||||
freq = clk_round_rate(max98088->mclk, freq);
|
||||
clk_set_rate(max98088->mclk, freq);
|
||||
}
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
|
||||
* 0x02 (when master clk is 20MHz to 30MHz)..
|
||||
@ -1310,6 +1317,20 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/*
|
||||
* SND_SOC_BIAS_PREPARE is called while preparing for a
|
||||
* transition to ON or away from ON. If current bias_level
|
||||
* is SND_SOC_BIAS_ON, then it is preparing for a transition
|
||||
* away from ON. Disable the clock in that case, otherwise
|
||||
* enable it.
|
||||
*/
|
||||
if (!IS_ERR(max98088->mclk)) {
|
||||
if (snd_soc_component_get_bias_level(component) ==
|
||||
SND_SOC_BIAS_ON)
|
||||
clk_disable_unprepare(max98088->mclk);
|
||||
else
|
||||
clk_prepare_enable(max98088->mclk);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
@ -1725,6 +1746,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
|
||||
if (IS_ERR(max98088->regmap))
|
||||
return PTR_ERR(max98088->regmap);
|
||||
|
||||
max98088->mclk = devm_clk_get(&i2c->dev, "mclk");
|
||||
if (IS_ERR(max98088->mclk))
|
||||
if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER)
|
||||
return PTR_ERR(max98088->mclk);
|
||||
|
||||
max98088->devtype = id->driver_data;
|
||||
|
||||
i2c_set_clientdata(i2c, max98088);
|
||||
@ -1742,9 +1768,19 @@ static const struct i2c_device_id max98088_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id max98088_of_match[] = {
|
||||
{ .compatible = "maxim,max98088" },
|
||||
{ .compatible = "maxim,max98089" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max98088_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver max98088_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max98088",
|
||||
.of_match_table = of_match_ptr(max98088_of_match),
|
||||
},
|
||||
.probe = max98088_i2c_probe,
|
||||
.id_table = max98088_i2c_id,
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Copyright (c) 2017, Maxim Integrated
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -454,7 +455,7 @@ SND_SOC_DAPM_SIGGEN("IMON"),
|
||||
SND_SOC_DAPM_SIGGEN("FBMON"),
|
||||
};
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0);
|
||||
static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1);
|
||||
static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
|
||||
0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
|
||||
9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
|
||||
@ -470,19 +471,19 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
|
||||
0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
|
||||
);
|
||||
static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
|
||||
2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0),
|
||||
8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0),
|
||||
10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0),
|
||||
12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
|
||||
14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
|
||||
0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0),
|
||||
2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0),
|
||||
5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0),
|
||||
7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0),
|
||||
10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0),
|
||||
14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0),
|
||||
);
|
||||
static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
|
||||
0, 15, TLV_DB_SCALE_ITEM(0, -100, 0),
|
||||
0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0),
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
|
||||
0, 60, TLV_DB_SCALE_ITEM(0, -25, 0),
|
||||
0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0),
|
||||
);
|
||||
|
||||
static bool max98373_readable_register(struct device *dev, unsigned int reg)
|
||||
@ -604,7 +605,7 @@ SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
|
||||
SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
|
||||
MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
|
||||
SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
|
||||
0, 0x7F, 0, max98373_digital_tlv),
|
||||
0, 0x7F, 1, max98373_digital_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
|
||||
MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
|
||||
SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
|
||||
@ -616,7 +617,7 @@ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
|
||||
SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
|
||||
MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
|
||||
SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
|
||||
MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv),
|
||||
MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv),
|
||||
SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
|
||||
MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
|
||||
SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
|
||||
@ -653,29 +654,29 @@ SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
|
||||
SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
|
||||
SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
|
||||
0, 0x3C, 0, max98373_bde_gain_tlv),
|
||||
0, 0x3C, 1, max98373_bde_gain_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
|
||||
0, 0xF, 0, max98373_limiter_thresh_tlv),
|
||||
0, 0xF, 1, max98373_limiter_thresh_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
|
||||
0, 0xF, 0, max98373_limiter_thresh_tlv),
|
||||
0, 0xF, 1, max98373_limiter_thresh_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
|
||||
0, 0xF, 0, max98373_limiter_thresh_tlv),
|
||||
0, 0xF, 1, max98373_limiter_thresh_tlv),
|
||||
SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
|
||||
0, 0xF, 0, max98373_limiter_thresh_tlv),
|
||||
0, 0xF, 1, max98373_limiter_thresh_tlv),
|
||||
/* Limiter */
|
||||
SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
|
||||
MAX98373_LIMITER_EN_SHIFT, 1, 0),
|
||||
|
1136
sound/soc/codecs/nau8822.c
Normal file
1136
sound/soc/codecs/nau8822.c
Normal file
File diff suppressed because it is too large
Load Diff
204
sound/soc/codecs/nau8822.h
Normal file
204
sound/soc/codecs/nau8822.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* nau8822.h -- NAU8822 Soc Audio Codec driver
|
||||
*
|
||||
* Author: David Lin <ctlin0@nuvoton.com>
|
||||
* Co-author: John Hsu <kchsu0@nuvoton.com>
|
||||
* Co-author: Seven Li <wtli@nuvoton.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 __NAU8822_H__
|
||||
#define __NAU8822_H__
|
||||
|
||||
#define NAU8822_REG_RESET 0x00
|
||||
#define NAU8822_REG_POWER_MANAGEMENT_1 0x01
|
||||
#define NAU8822_REG_POWER_MANAGEMENT_2 0x02
|
||||
#define NAU8822_REG_POWER_MANAGEMENT_3 0x03
|
||||
#define NAU8822_REG_AUDIO_INTERFACE 0x04
|
||||
#define NAU8822_REG_COMPANDING_CONTROL 0x05
|
||||
#define NAU8822_REG_CLOCKING 0x06
|
||||
#define NAU8822_REG_ADDITIONAL_CONTROL 0x07
|
||||
#define NAU8822_REG_GPIO_CONTROL 0x08
|
||||
#define NAU8822_REG_JACK_DETECT_CONTROL_1 0x09
|
||||
#define NAU8822_REG_DAC_CONTROL 0x0A
|
||||
#define NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME 0x0B
|
||||
#define NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME 0x0C
|
||||
#define NAU8822_REG_JACK_DETECT_CONTROL_2 0x0D
|
||||
#define NAU8822_REG_ADC_CONTROL 0x0E
|
||||
#define NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME 0x0F
|
||||
#define NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME 0x10
|
||||
#define NAU8822_REG_EQ1 0x12
|
||||
#define NAU8822_REG_EQ2 0x13
|
||||
#define NAU8822_REG_EQ3 0x14
|
||||
#define NAU8822_REG_EQ4 0x15
|
||||
#define NAU8822_REG_EQ5 0x16
|
||||
#define NAU8822_REG_DAC_LIMITER_1 0x18
|
||||
#define NAU8822_REG_DAC_LIMITER_2 0x19
|
||||
#define NAU8822_REG_NOTCH_FILTER_1 0x1B
|
||||
#define NAU8822_REG_NOTCH_FILTER_2 0x1C
|
||||
#define NAU8822_REG_NOTCH_FILTER_3 0x1D
|
||||
#define NAU8822_REG_NOTCH_FILTER_4 0x1E
|
||||
#define NAU8822_REG_ALC_CONTROL_1 0x20
|
||||
#define NAU8822_REG_ALC_CONTROL_2 0x21
|
||||
#define NAU8822_REG_ALC_CONTROL_3 0x22
|
||||
#define NAU8822_REG_NOISE_GATE 0x23
|
||||
#define NAU8822_REG_PLL_N 0x24
|
||||
#define NAU8822_REG_PLL_K1 0x25
|
||||
#define NAU8822_REG_PLL_K2 0x26
|
||||
#define NAU8822_REG_PLL_K3 0x27
|
||||
#define NAU8822_REG_3D_CONTROL 0x29
|
||||
#define NAU8822_REG_RIGHT_SPEAKER_CONTROL 0x2B
|
||||
#define NAU8822_REG_INPUT_CONTROL 0x2C
|
||||
#define NAU8822_REG_LEFT_INP_PGA_CONTROL 0x2D
|
||||
#define NAU8822_REG_RIGHT_INP_PGA_CONTROL 0x2E
|
||||
#define NAU8822_REG_LEFT_ADC_BOOST_CONTROL 0x2F
|
||||
#define NAU8822_REG_RIGHT_ADC_BOOST_CONTROL 0x30
|
||||
#define NAU8822_REG_OUTPUT_CONTROL 0x31
|
||||
#define NAU8822_REG_LEFT_MIXER_CONTROL 0x32
|
||||
#define NAU8822_REG_RIGHT_MIXER_CONTROL 0x33
|
||||
#define NAU8822_REG_LHP_VOLUME 0x34
|
||||
#define NAU8822_REG_RHP_VOLUME 0x35
|
||||
#define NAU8822_REG_LSPKOUT_VOLUME 0x36
|
||||
#define NAU8822_REG_RSPKOUT_VOLUME 0x37
|
||||
#define NAU8822_REG_AUX2_MIXER 0x38
|
||||
#define NAU8822_REG_AUX1_MIXER 0x39
|
||||
#define NAU8822_REG_POWER_MANAGEMENT_4 0x3A
|
||||
#define NAU8822_REG_LEFT_TIME_SLOT 0x3B
|
||||
#define NAU8822_REG_MISC 0x3C
|
||||
#define NAU8822_REG_RIGHT_TIME_SLOT 0x3D
|
||||
#define NAU8822_REG_DEVICE_REVISION 0x3E
|
||||
#define NAU8822_REG_DEVICE_ID 0x3F
|
||||
#define NAU8822_REG_DAC_DITHER 0x41
|
||||
#define NAU8822_REG_ALC_ENHANCE_1 0x46
|
||||
#define NAU8822_REG_ALC_ENHANCE_2 0x47
|
||||
#define NAU8822_REG_192KHZ_SAMPLING 0x48
|
||||
#define NAU8822_REG_MISC_CONTROL 0x49
|
||||
#define NAU8822_REG_INPUT_TIEOFF 0x4A
|
||||
#define NAU8822_REG_POWER_REDUCTION 0x4B
|
||||
#define NAU8822_REG_AGC_PEAK2PEAK 0x4C
|
||||
#define NAU8822_REG_AGC_PEAK_DETECT 0x4D
|
||||
#define NAU8822_REG_AUTOMUTE_CONTROL 0x4E
|
||||
#define NAU8822_REG_OUTPUT_TIEOFF 0x4F
|
||||
#define NAU8822_REG_MAX_REGISTER NAU8822_REG_OUTPUT_TIEOFF
|
||||
|
||||
/* NAU8822_REG_POWER_MANAGEMENT_1 (0x1) */
|
||||
#define NAU8822_REFIMP_MASK 0x3
|
||||
#define NAU8822_REFIMP_80K 0x1
|
||||
#define NAU8822_REFIMP_300K 0x2
|
||||
#define NAU8822_REFIMP_3K 0x3
|
||||
#define NAU8822_IOBUF_EN (0x1 << 2)
|
||||
#define NAU8822_ABIAS_EN (0x1 << 3)
|
||||
|
||||
/* NAU8822_REG_AUDIO_INTERFACE (0x4) */
|
||||
#define NAU8822_AIFMT_MASK (0x3 << 3)
|
||||
#define NAU8822_WLEN_MASK (0x3 << 5)
|
||||
#define NAU8822_WLEN_20 (0x1 << 5)
|
||||
#define NAU8822_WLEN_24 (0x2 << 5)
|
||||
#define NAU8822_WLEN_32 (0x3 << 5)
|
||||
#define NAU8822_LRP_MASK (0x1 << 7)
|
||||
#define NAU8822_BCLKP_MASK (0x1 << 8)
|
||||
|
||||
/* NAU8822_REG_COMPANDING_CONTROL (0x5) */
|
||||
#define NAU8822_ADDAP_SFT 0
|
||||
#define NAU8822_ADCCM_SFT 1
|
||||
#define NAU8822_DACCM_SFT 3
|
||||
|
||||
/* NAU8822_REG_CLOCKING (0x6) */
|
||||
#define NAU8822_CLKIOEN_MASK 0x1
|
||||
#define NAU8822_MCLKSEL_SFT 5
|
||||
#define NAU8822_MCLKSEL_MASK (0x7 << 5)
|
||||
#define NAU8822_BCLKSEL_SFT 2
|
||||
#define NAU8822_BCLKSEL_MASK (0x7 << 2)
|
||||
#define NAU8822_CLKM_MASK (0x1 << 8)
|
||||
#define NAU8822_CLKM_MCLK (0x0 << 8)
|
||||
#define NAU8822_CLKM_PLL (0x1 << 8)
|
||||
|
||||
/* NAU8822_REG_ADDITIONAL_CONTROL (0x08) */
|
||||
#define NAU8822_SMPLR_SFT 1
|
||||
#define NAU8822_SMPLR_MASK (0x7 << 1)
|
||||
#define NAU8822_SMPLR_48K (0x0 << 1)
|
||||
#define NAU8822_SMPLR_32K (0x1 << 1)
|
||||
#define NAU8822_SMPLR_24K (0x2 << 1)
|
||||
#define NAU8822_SMPLR_16K (0x3 << 1)
|
||||
#define NAU8822_SMPLR_12K (0x4 << 1)
|
||||
#define NAU8822_SMPLR_8K (0x5 << 1)
|
||||
|
||||
/* NAU8822_REG_EQ1 (0x12) */
|
||||
#define NAU8822_EQ1GC_SFT 0
|
||||
#define NAU8822_EQ1CF_SFT 5
|
||||
#define NAU8822_EQM_SFT 8
|
||||
|
||||
/* NAU8822_REG_EQ2 (0x13) */
|
||||
#define NAU8822_EQ2GC_SFT 0
|
||||
#define NAU8822_EQ2CF_SFT 5
|
||||
#define NAU8822_EQ2BW_SFT 8
|
||||
|
||||
/* NAU8822_REG_EQ3 (0x14) */
|
||||
#define NAU8822_EQ3GC_SFT 0
|
||||
#define NAU8822_EQ3CF_SFT 5
|
||||
#define NAU8822_EQ3BW_SFT 8
|
||||
|
||||
/* NAU8822_REG_EQ4 (0x15) */
|
||||
#define NAU8822_EQ4GC_SFT 0
|
||||
#define NAU8822_EQ4CF_SFT 5
|
||||
#define NAU8822_EQ4BW_SFT 8
|
||||
|
||||
/* NAU8822_REG_EQ5 (0x16) */
|
||||
#define NAU8822_EQ5GC_SFT 0
|
||||
#define NAU8822_EQ5CF_SFT 5
|
||||
|
||||
/* NAU8822_REG_ALC_CONTROL_1 (0x20) */
|
||||
#define NAU8822_ALCMINGAIN_SFT 0
|
||||
#define NAU8822_ALCMXGAIN_SFT 3
|
||||
#define NAU8822_ALCEN_SFT 7
|
||||
|
||||
/* NAU8822_REG_ALC_CONTROL_2 (0x21) */
|
||||
#define NAU8822_ALCSL_SFT 0
|
||||
#define NAU8822_ALCHT_SFT 4
|
||||
|
||||
/* NAU8822_REG_ALC_CONTROL_3 (0x22) */
|
||||
#define NAU8822_ALCATK_SFT 0
|
||||
#define NAU8822_ALCDCY_SFT 4
|
||||
#define NAU8822_ALCM_SFT 8
|
||||
|
||||
/* NAU8822_REG_PLL_N (0x24) */
|
||||
#define NAU8822_PLLMCLK_DIV2 (0x1 << 4)
|
||||
#define NAU8822_PLLN_MASK 0xF
|
||||
|
||||
#define NAU8822_PLLK1_SFT 18
|
||||
#define NAU8822_PLLK1_MASK 0x3F
|
||||
|
||||
/* NAU8822_REG_PLL_K2 (0x26) */
|
||||
#define NAU8822_PLLK2_SFT 9
|
||||
#define NAU8822_PLLK2_MASK 0x1FF
|
||||
|
||||
/* NAU8822_REG_PLL_K3 (0x27) */
|
||||
#define NAU8822_PLLK3_MASK 0x1FF
|
||||
|
||||
/* System Clock Source */
|
||||
enum {
|
||||
NAU8822_CLK_MCLK,
|
||||
NAU8822_CLK_PLL,
|
||||
};
|
||||
|
||||
struct nau8822_pll {
|
||||
int pre_factor;
|
||||
int mclk_scaler;
|
||||
int pll_frac;
|
||||
int pll_int;
|
||||
};
|
||||
|
||||
/* Codec Private Data */
|
||||
struct nau8822 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
int mclk_idx;
|
||||
struct nau8822_pll pll;
|
||||
int sysclk;
|
||||
int div_id;
|
||||
};
|
||||
|
||||
#endif /* __NAU8822_H__ */
|
@ -401,7 +401,8 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
priv->tdm_offset += 1;
|
||||
/* Fall through... DSP_A uses the same basic config as DSP_B
|
||||
/* fall through */
|
||||
/* DSP_A uses the same basic config as DSP_B
|
||||
* except we need to shift the TDM output by one BCK cycle
|
||||
*/
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
|
60
sound/soc/codecs/pcm3060-i2c.c
Normal file
60
sound/soc/codecs/pcm3060-i2c.c
Normal file
@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// PCM3060 I2C driver
|
||||
//
|
||||
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "pcm3060.h"
|
||||
|
||||
static int pcm3060_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pcm3060_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, priv);
|
||||
|
||||
priv->regmap = devm_regmap_init_i2c(i2c, &pcm3060_regmap);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
return pcm3060_probe(&i2c->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pcm3060_i2c_id[] = {
|
||||
{ .name = "pcm3060" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcm3060_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcm3060_of_match[] = {
|
||||
{ .compatible = "ti,pcm3060" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcm3060_of_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct i2c_driver pcm3060_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "pcm3060",
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = pcm3060_of_match,
|
||||
#endif /* CONFIG_OF */
|
||||
},
|
||||
.id_table = pcm3060_i2c_id,
|
||||
.probe = pcm3060_i2c_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(pcm3060_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("PCM3060 I2C driver");
|
||||
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
|
||||
MODULE_LICENSE("GPL v2");
|
59
sound/soc/codecs/pcm3060-spi.c
Normal file
59
sound/soc/codecs/pcm3060-spi.c
Normal file
@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// PCM3060 SPI driver
|
||||
//
|
||||
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "pcm3060.h"
|
||||
|
||||
static int pcm3060_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct pcm3060_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_set_drvdata(spi, priv);
|
||||
|
||||
priv->regmap = devm_regmap_init_spi(spi, &pcm3060_regmap);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
return pcm3060_probe(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id pcm3060_spi_id[] = {
|
||||
{ .name = "pcm3060" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, pcm3060_spi_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcm3060_of_match[] = {
|
||||
{ .compatible = "ti,pcm3060" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcm3060_of_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct spi_driver pcm3060_spi_driver = {
|
||||
.driver = {
|
||||
.name = "pcm3060",
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = pcm3060_of_match,
|
||||
#endif /* CONFIG_OF */
|
||||
},
|
||||
.id_table = pcm3060_spi_id,
|
||||
.probe = pcm3060_spi_probe,
|
||||
};
|
||||
|
||||
module_spi_driver(pcm3060_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("PCM3060 SPI driver");
|
||||
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
|
||||
MODULE_LICENSE("GPL v2");
|
295
sound/soc/codecs/pcm3060.c
Normal file
295
sound/soc/codecs/pcm3060.c
Normal file
@ -0,0 +1,295 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// PCM3060 codec driver
|
||||
//
|
||||
// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "pcm3060.h"
|
||||
|
||||
/* dai */
|
||||
|
||||
static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_component *comp = dai->component;
|
||||
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
|
||||
|
||||
if (dir != SND_SOC_CLOCK_IN) {
|
||||
dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->dai[dai->id].sclk_freq = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_component *comp = dai->component;
|
||||
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
|
||||
unsigned int reg;
|
||||
unsigned int val;
|
||||
|
||||
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
|
||||
dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
priv->dai[dai->id].is_master = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
priv->dai[dai->id].is_master = false;
|
||||
break;
|
||||
default:
|
||||
dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = PCM3060_REG_FMT_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
val = PCM3060_REG_FMT_RJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val = PCM3060_REG_FMT_LJ;
|
||||
break;
|
||||
default:
|
||||
dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dai->id == PCM3060_DAI_ID_DAC)
|
||||
reg = PCM3060_REG67;
|
||||
else
|
||||
reg = PCM3060_REG72;
|
||||
|
||||
regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3060_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *comp = dai->component;
|
||||
struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
|
||||
unsigned int rate;
|
||||
unsigned int ratio;
|
||||
unsigned int reg;
|
||||
unsigned int val;
|
||||
|
||||
if (!priv->dai[dai->id].is_master) {
|
||||
val = PCM3060_REG_MS_S;
|
||||
goto val_ready;
|
||||
}
|
||||
|
||||
rate = params_rate(params);
|
||||
if (!rate) {
|
||||
dev_err(comp->dev, "rate is not configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ratio = priv->dai[dai->id].sclk_freq / rate;
|
||||
|
||||
switch (ratio) {
|
||||
case 768:
|
||||
val = PCM3060_REG_MS_M768;
|
||||
break;
|
||||
case 512:
|
||||
val = PCM3060_REG_MS_M512;
|
||||
break;
|
||||
case 384:
|
||||
val = PCM3060_REG_MS_M384;
|
||||
break;
|
||||
case 256:
|
||||
val = PCM3060_REG_MS_M256;
|
||||
break;
|
||||
case 192:
|
||||
val = PCM3060_REG_MS_M192;
|
||||
break;
|
||||
case 128:
|
||||
val = PCM3060_REG_MS_M128;
|
||||
break;
|
||||
default:
|
||||
dev_err(comp->dev, "unsupported ratio: %d\n", ratio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val_ready:
|
||||
if (dai->id == PCM3060_DAI_ID_DAC)
|
||||
reg = PCM3060_REG67;
|
||||
else
|
||||
reg = PCM3060_REG72;
|
||||
|
||||
regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops pcm3060_dai_ops = {
|
||||
.set_sysclk = pcm3060_set_sysclk,
|
||||
.set_fmt = pcm3060_set_fmt,
|
||||
.hw_params = pcm3060_hw_params,
|
||||
};
|
||||
|
||||
#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
||||
|
||||
#define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
|
||||
|
||||
static struct snd_soc_dai_driver pcm3060_dai[] = {
|
||||
{
|
||||
.name = "pcm3060-dac",
|
||||
.id = PCM3060_DAI_ID_DAC,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = PCM3060_DAI_RATES_DAC,
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &pcm3060_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "pcm3060-adc",
|
||||
.id = PCM3060_DAI_ID_ADC,
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = PCM3060_DAI_RATES_ADC,
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &pcm3060_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/* dapm */
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1);
|
||||
|
||||
static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
|
||||
SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume",
|
||||
PCM3060_REG65, PCM3060_REG66, 0,
|
||||
PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX,
|
||||
0, pcm3060_dapm_tlv),
|
||||
SOC_DOUBLE("Master Playback Switch", PCM3060_REG68,
|
||||
PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1),
|
||||
|
||||
SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume",
|
||||
PCM3060_REG70, PCM3060_REG71, 0,
|
||||
PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX,
|
||||
0, pcm3060_dapm_tlv),
|
||||
SOC_DOUBLE("Master Capture Switch", PCM3060_REG73,
|
||||
PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("OUTL+"),
|
||||
SND_SOC_DAPM_OUTPUT("OUTR+"),
|
||||
SND_SOC_DAPM_OUTPUT("OUTL-"),
|
||||
SND_SOC_DAPM_OUTPUT("OUTR-"),
|
||||
|
||||
SND_SOC_DAPM_INPUT("INL"),
|
||||
SND_SOC_DAPM_INPUT("INR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
|
||||
{ "OUTL+", NULL, "Playback" },
|
||||
{ "OUTR+", NULL, "Playback" },
|
||||
{ "OUTL-", NULL, "Playback" },
|
||||
{ "OUTR-", NULL, "Playback" },
|
||||
|
||||
{ "Capture", NULL, "INL" },
|
||||
{ "Capture", NULL, "INR" },
|
||||
};
|
||||
|
||||
/* soc component */
|
||||
|
||||
static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
|
||||
.controls = pcm3060_dapm_controls,
|
||||
.num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
|
||||
.dapm_widgets = pcm3060_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
|
||||
.dapm_routes = pcm3060_dapm_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
|
||||
};
|
||||
|
||||
/* regmap */
|
||||
|
||||
static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg >= PCM3060_REG64);
|
||||
}
|
||||
|
||||
static bool pcm3060_reg_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg >= PCM3060_REG64);
|
||||
}
|
||||
|
||||
static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* PCM3060_REG64 is volatile */
|
||||
return (reg == PCM3060_REG64);
|
||||
}
|
||||
|
||||
static const struct reg_default pcm3060_reg_defaults[] = {
|
||||
{ PCM3060_REG64, 0xF0 },
|
||||
{ PCM3060_REG65, 0xFF },
|
||||
{ PCM3060_REG66, 0xFF },
|
||||
{ PCM3060_REG67, 0x00 },
|
||||
{ PCM3060_REG68, 0x00 },
|
||||
{ PCM3060_REG69, 0x00 },
|
||||
{ PCM3060_REG70, 0xD7 },
|
||||
{ PCM3060_REG71, 0xD7 },
|
||||
{ PCM3060_REG72, 0x00 },
|
||||
{ PCM3060_REG73, 0x00 },
|
||||
};
|
||||
|
||||
const struct regmap_config pcm3060_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = pcm3060_reg_writeable,
|
||||
.readable_reg = pcm3060_reg_readable,
|
||||
.volatile_reg = pcm3060_reg_volatile,
|
||||
.max_register = PCM3060_REG73,
|
||||
.reg_defaults = pcm3060_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL(pcm3060_regmap);
|
||||
|
||||
/* device */
|
||||
|
||||
int pcm3060_probe(struct device *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
|
||||
pcm3060_dai,
|
||||
ARRAY_SIZE(pcm3060_dai));
|
||||
if (rc) {
|
||||
dev_err(dev, "failed to register component, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pcm3060_probe);
|
||||
|
||||
MODULE_DESCRIPTION("PCM3060 codec driver");
|
||||
MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
|
||||
MODULE_LICENSE("GPL v2");
|
88
sound/soc/codecs/pcm3060.h
Normal file
88
sound/soc/codecs/pcm3060.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* PCM3060 codec driver
|
||||
*
|
||||
* Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
|
||||
*/
|
||||
|
||||
#ifndef _SND_SOC_PCM3060_H
|
||||
#define _SND_SOC_PCM3060_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
extern const struct regmap_config pcm3060_regmap;
|
||||
|
||||
#define PCM3060_DAI_ID_DAC 0
|
||||
#define PCM3060_DAI_ID_ADC 1
|
||||
#define PCM3060_DAI_IDS_NUM 2
|
||||
|
||||
struct pcm3060_priv_dai {
|
||||
bool is_master;
|
||||
unsigned int sclk_freq;
|
||||
};
|
||||
|
||||
struct pcm3060_priv {
|
||||
struct regmap *regmap;
|
||||
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
|
||||
};
|
||||
|
||||
int pcm3060_probe(struct device *dev);
|
||||
int pcm3060_remove(struct device *dev);
|
||||
|
||||
/* registers */
|
||||
|
||||
#define PCM3060_REG64 0x40
|
||||
#define PCM3060_REG_MRST 0x80
|
||||
#define PCM3060_REG_SRST 0x40
|
||||
#define PCM3060_REG_ADPSV 0x20
|
||||
#define PCM3060_REG_DAPSV 0x10
|
||||
#define PCM3060_REG_SE 0x01
|
||||
|
||||
#define PCM3060_REG65 0x41
|
||||
#define PCM3060_REG66 0x42
|
||||
#define PCM3060_REG_AT2_MIN 0x36
|
||||
#define PCM3060_REG_AT2_MAX 0xFF
|
||||
|
||||
#define PCM3060_REG67 0x43
|
||||
#define PCM3060_REG72 0x48
|
||||
#define PCM3060_REG_CSEL 0x80
|
||||
#define PCM3060_REG_MASK_MS 0x70
|
||||
#define PCM3060_REG_MS_S 0x00
|
||||
#define PCM3060_REG_MS_M768 (0x01 << 4)
|
||||
#define PCM3060_REG_MS_M512 (0x02 << 4)
|
||||
#define PCM3060_REG_MS_M384 (0x03 << 4)
|
||||
#define PCM3060_REG_MS_M256 (0x04 << 4)
|
||||
#define PCM3060_REG_MS_M192 (0x05 << 4)
|
||||
#define PCM3060_REG_MS_M128 (0x06 << 4)
|
||||
#define PCM3060_REG_MASK_FMT 0x03
|
||||
#define PCM3060_REG_FMT_I2S 0x00
|
||||
#define PCM3060_REG_FMT_LJ 0x01
|
||||
#define PCM3060_REG_FMT_RJ 0x02
|
||||
|
||||
#define PCM3060_REG68 0x44
|
||||
#define PCM3060_REG_OVER 0x40
|
||||
#define PCM3060_REG_DREV2 0x04
|
||||
#define PCM3060_REG_SHIFT_MUT21 0x00
|
||||
#define PCM3060_REG_SHIFT_MUT22 0x01
|
||||
|
||||
#define PCM3060_REG69 0x45
|
||||
#define PCM3060_REG_FLT 0x80
|
||||
#define PCM3060_REG_MASK_DMF 0x60
|
||||
#define PCM3060_REG_DMC 0x10
|
||||
#define PCM3060_REG_ZREV 0x02
|
||||
#define PCM3060_REG_AZRO 0x01
|
||||
|
||||
#define PCM3060_REG70 0x46
|
||||
#define PCM3060_REG71 0x47
|
||||
#define PCM3060_REG_AT1_MIN 0x0E
|
||||
#define PCM3060_REG_AT1_MAX 0xFF
|
||||
|
||||
#define PCM3060_REG73 0x49
|
||||
#define PCM3060_REG_ZCDD 0x10
|
||||
#define PCM3060_REG_BYP 0x08
|
||||
#define PCM3060_REG_DREV1 0x04
|
||||
#define PCM3060_REG_SHIFT_MUT11 0x00
|
||||
#define PCM3060_REG_SHIFT_MUT12 0x01
|
||||
|
||||
#endif /* _SND_SOC_PCM3060_H */
|
@ -33,6 +33,8 @@
|
||||
#define PCM3168A_FMT_RIGHT_J_16 0x3
|
||||
#define PCM3168A_FMT_DSP_A 0x4
|
||||
#define PCM3168A_FMT_DSP_B 0x5
|
||||
#define PCM3168A_FMT_I2S_TDM 0x6
|
||||
#define PCM3168A_FMT_LEFT_J_TDM 0x7
|
||||
#define PCM3168A_FMT_DSP_MASK 0x4
|
||||
|
||||
#define PCM3168A_NUM_SUPPLIES 6
|
||||
@ -401,9 +403,11 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
bool tx, master_mode;
|
||||
u32 val, mask, shift, reg;
|
||||
unsigned int rate, fmt, ratio, max_ratio;
|
||||
unsigned int chan;
|
||||
int i, min_frame_size;
|
||||
|
||||
rate = params_rate(params);
|
||||
chan = params_channels(params);
|
||||
|
||||
ratio = pcm3168a->sysclk / rate;
|
||||
|
||||
@ -456,6 +460,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* for TDM */
|
||||
if (chan > 2) {
|
||||
switch (fmt) {
|
||||
case PCM3168A_FMT_I2S:
|
||||
fmt = PCM3168A_FMT_I2S_TDM;
|
||||
break;
|
||||
case PCM3168A_FMT_LEFT_J:
|
||||
fmt = PCM3168A_FMT_LEFT_J_TDM;
|
||||
break;
|
||||
default:
|
||||
dev_err(component->dev, "TDM is supported under I2S/Left_J only\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (master_mode)
|
||||
val = ((i + 1) << shift);
|
||||
else
|
||||
@ -476,7 +495,69 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
unsigned int fmt;
|
||||
unsigned int sample_min;
|
||||
unsigned int channel_max;
|
||||
|
||||
if (tx)
|
||||
fmt = pcm3168a->dac_fmt;
|
||||
else
|
||||
fmt = pcm3168a->adc_fmt;
|
||||
|
||||
/*
|
||||
* Available Data Bits
|
||||
*
|
||||
* RIGHT_J : 24 / 16
|
||||
* LEFT_J : 24
|
||||
* I2S : 24
|
||||
*
|
||||
* TDM available
|
||||
*
|
||||
* I2S
|
||||
* LEFT_J
|
||||
*/
|
||||
switch (fmt) {
|
||||
case PCM3168A_FMT_RIGHT_J:
|
||||
sample_min = 16;
|
||||
channel_max = 2;
|
||||
break;
|
||||
case PCM3168A_FMT_LEFT_J:
|
||||
sample_min = 24;
|
||||
if (tx)
|
||||
channel_max = 8;
|
||||
else
|
||||
channel_max = 6;
|
||||
break;
|
||||
case PCM3168A_FMT_I2S:
|
||||
sample_min = 24;
|
||||
if (tx)
|
||||
channel_max = 8;
|
||||
else
|
||||
channel_max = 6;
|
||||
break;
|
||||
default:
|
||||
sample_min = 24;
|
||||
channel_max = 2;
|
||||
}
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
|
||||
sample_min, 32);
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
2, channel_max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
|
||||
.startup = pcm3168a_startup,
|
||||
.set_fmt = pcm3168a_set_dai_fmt_dac,
|
||||
.set_sysclk = pcm3168a_set_dai_sysclk,
|
||||
.hw_params = pcm3168a_hw_params,
|
||||
@ -484,6 +565,7 @@ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
|
||||
.startup = pcm3168a_startup,
|
||||
.set_fmt = pcm3168a_set_dai_fmt_adc,
|
||||
.set_sysclk = pcm3168a_set_dai_sysclk,
|
||||
.hw_params = pcm3168a_hw_params
|
||||
|
@ -755,6 +755,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
break;
|
||||
default:
|
||||
dev_warn(component->dev, "invalid pll source, use BCLK\n");
|
||||
/* fall through */
|
||||
case RT274_PLL2_S_BCLK:
|
||||
snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
|
||||
RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
|
||||
@ -782,6 +783,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
break;
|
||||
default:
|
||||
dev_warn(component->dev, "invalid freq_in, assume 4.8M\n");
|
||||
/* fall through */
|
||||
case 100:
|
||||
snd_soc_component_write(component, 0x7a, 0xaab6);
|
||||
snd_soc_component_write(component, 0x7b, 0x0301);
|
||||
|
@ -10,7 +10,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
|
@ -72,6 +72,7 @@ struct rt5663_priv {
|
||||
static const struct reg_sequence rt5663_patch_list[] = {
|
||||
{ 0x002a, 0x8020 },
|
||||
{ 0x0086, 0x0028 },
|
||||
{ 0x0100, 0xa020 },
|
||||
{ 0x0117, 0x0f28 },
|
||||
{ 0x02fb, 0x8089 },
|
||||
};
|
||||
@ -580,7 +581,7 @@ static const struct reg_default rt5663_reg[] = {
|
||||
{ 0x00fd, 0x0001 },
|
||||
{ 0x00fe, 0x10ec },
|
||||
{ 0x00ff, 0x6406 },
|
||||
{ 0x0100, 0xa0a0 },
|
||||
{ 0x0100, 0xa020 },
|
||||
{ 0x0108, 0x4444 },
|
||||
{ 0x0109, 0x4444 },
|
||||
{ 0x010a, 0xaaaa },
|
||||
@ -2337,6 +2338,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
|
||||
0x8000);
|
||||
snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000,
|
||||
0x3000);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5663_DIG_VOL_ZCD, 0x00c0, 0x0080);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2351,6 +2354,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
|
||||
RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5663_DACREF_LDO, 0x3e0e, 0);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5663_DIG_VOL_ZCD, 0x00c0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2587,17 +2587,10 @@ static int rt5668_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
}
|
||||
|
||||
return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
|
||||
return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
|
||||
rt5668_dai, ARRAY_SIZE(rt5668_dai));
|
||||
}
|
||||
|
||||
static int rt5668_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_component(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5668_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct rt5668_priv *rt5668 = i2c_get_clientdata(client);
|
||||
@ -2628,7 +2621,6 @@ static struct i2c_driver rt5668_i2c_driver = {
|
||||
.acpi_match_table = ACPI_PTR(rt5668_acpi_match),
|
||||
},
|
||||
.probe = rt5668_i2c_probe,
|
||||
.remove = rt5668_i2c_remove,
|
||||
.shutdown = rt5668_i2c_shutdown,
|
||||
.id_table = rt5668_i2c_id,
|
||||
};
|
||||
|
@ -2875,6 +2875,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Lenovo Thinkpad Tablet 8",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC2_INR |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE1),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Lenovo Thinkpad Tablet 10",
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
@ -67,7 +67,8 @@ struct rt5682_priv {
|
||||
};
|
||||
|
||||
static const struct reg_sequence patch_list[] = {
|
||||
{0x01c1, 0x1000},
|
||||
{RT5682_HP_IMP_SENS_CTRL_19, 0x1000},
|
||||
{RT5682_DAC_ADC_DIG_VOL1, 0xa020},
|
||||
};
|
||||
|
||||
static const struct reg_default rt5682_reg[] = {
|
||||
@ -1432,6 +1433,28 @@ static const struct snd_kcontrol_new hpor_switch =
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
|
||||
RT5682_R_MUTE_SFT, 1, 1);
|
||||
|
||||
static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
@ -1444,10 +1467,10 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
|
||||
RT5682_HP_LOGIC_CTRL_2, 0x0012);
|
||||
snd_soc_component_write(component,
|
||||
RT5682_HP_CTRL_2, 0x6000);
|
||||
snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1,
|
||||
RT5682_NG2_EN_MASK, RT5682_NG2_EN);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5682_DEPOP_1, 0x60, 0x60);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
@ -1455,6 +1478,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
|
||||
RT5682_DEPOP_1, 0x60, 0x0);
|
||||
snd_soc_component_write(component,
|
||||
RT5682_HP_CTRL_2, 0x0000);
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1718,7 +1743,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1,
|
||||
RT5682_PWR_HA_R_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1,
|
||||
RT5682_PUMP_EN_SFT, 0, NULL, 0),
|
||||
RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1,
|
||||
RT5682_CAPLESS_EN_SFT, 0, NULL, 0),
|
||||
|
||||
@ -1879,6 +1905,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
|
||||
{"HP Amp", NULL, "Charge Pump"},
|
||||
{"HP Amp", NULL, "CLKDET SYS"},
|
||||
{"HP Amp", NULL, "CBJ Power"},
|
||||
{"HP Amp", NULL, "Vref1"},
|
||||
{"HP Amp", NULL, "Vref2"},
|
||||
{"HPOL Playback", "Switch", "HP Amp"},
|
||||
{"HPOR Playback", "Switch", "HP Amp"},
|
||||
@ -2446,30 +2473,23 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
mutex_lock(&rt5682->calibrate_mutex);
|
||||
|
||||
rt5682_reset(rt5682->regmap);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af);
|
||||
usleep_range(15000, 20000);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
|
||||
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
|
||||
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300);
|
||||
regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800);
|
||||
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
|
||||
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
|
||||
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005);
|
||||
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
|
||||
regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
|
||||
regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
|
||||
regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
|
||||
regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
|
||||
|
||||
@ -2485,8 +2505,12 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
pr_err("HP Calibration Failure\n");
|
||||
|
||||
/* restore settings */
|
||||
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0080);
|
||||
regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000);
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
|
||||
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000);
|
||||
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
|
||||
|
||||
mutex_unlock(&rt5682->calibrate_mutex);
|
||||
|
||||
@ -2560,7 +2584,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
rt5682_calibrate(rt5682);
|
||||
|
||||
ret = regmap_register_patch(rt5682->regmap, patch_list,
|
||||
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
|
||||
ARRAY_SIZE(patch_list));
|
||||
if (ret != 0)
|
||||
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
|
||||
@ -2614,6 +2638,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
|
||||
RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
|
||||
RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
|
||||
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
|
||||
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
|
||||
|
||||
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
|
||||
rt5682_jack_detect_handler);
|
||||
@ -2631,11 +2659,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_component_dev_rt5682,
|
||||
return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5682,
|
||||
rt5682_dai, ARRAY_SIZE(rt5682_dai));
|
||||
}
|
||||
|
||||
static int rt5682_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_component(&i2c->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5682_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
|
||||
@ -2666,6 +2700,7 @@ static struct i2c_driver rt5682_i2c_driver = {
|
||||
.acpi_match_table = ACPI_PTR(rt5682_acpi_match),
|
||||
},
|
||||
.probe = rt5682_i2c_probe,
|
||||
.remove = rt5682_i2c_remove,
|
||||
.shutdown = rt5682_i2c_shutdown,
|
||||
.id_table = rt5682_i2c_id,
|
||||
};
|
||||
|
@ -1214,6 +1214,20 @@
|
||||
#define RT5682_JDH_NO_PLUG (0x1 << 4)
|
||||
#define RT5682_JDH_PLUG (0x0 << 4)
|
||||
|
||||
/* Bias current control 8 (0x0111) */
|
||||
#define RT5682_HPA_CP_BIAS_CTRL_MASK (0x3 << 2)
|
||||
#define RT5682_HPA_CP_BIAS_2UA (0x0 << 2)
|
||||
#define RT5682_HPA_CP_BIAS_3UA (0x1 << 2)
|
||||
#define RT5682_HPA_CP_BIAS_4UA (0x2 << 2)
|
||||
#define RT5682_HPA_CP_BIAS_6UA (0x3 << 2)
|
||||
|
||||
/* Charge Pump Internal Register1 (0x0125) */
|
||||
#define RT5682_CP_CLK_HP_MASK (0x3 << 4)
|
||||
#define RT5682_CP_CLK_HP_100KHZ (0x0 << 4)
|
||||
#define RT5682_CP_CLK_HP_200KHZ (0x1 << 4)
|
||||
#define RT5682_CP_CLK_HP_300KHZ (0x2 << 4)
|
||||
#define RT5682_CP_CLK_HP_600KHZ (0x3 << 4)
|
||||
|
||||
/* Chopper and Clock control for DAC (0x013a)*/
|
||||
#define RT5682_CKXEN_DAC1_MASK (0x1 << 13)
|
||||
#define RT5682_CKXEN_DAC1_SFT 13
|
||||
|
@ -1218,7 +1218,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component)
|
||||
* Searching for a suitable index solving this formula:
|
||||
* idx = 40 * log10(vag_val / lo_cagcntrl) + 15
|
||||
*/
|
||||
vol_quot = (vag * 100) / lo_vag;
|
||||
vol_quot = lo_vag ? (vag * 100) / lo_vag : 0;
|
||||
lo_vol = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
|
||||
if (vol_quot >= vol_quot_table[i])
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -142,6 +143,7 @@ static const char *sta32x_supply_names[] = {
|
||||
/* codec private data */
|
||||
struct sta32x_priv {
|
||||
struct regmap *regmap;
|
||||
struct clk *xti_clk;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
|
||||
struct snd_soc_component *component;
|
||||
struct sta32x_platform_data *pdata;
|
||||
@ -882,6 +884,15 @@ static int sta32x_probe(struct snd_soc_component *component)
|
||||
|
||||
sta32x->component = component;
|
||||
|
||||
if (sta32x->xti_clk) {
|
||||
ret = clk_prepare_enable(sta32x->xti_clk);
|
||||
if (ret != 0) {
|
||||
dev_err(component->dev,
|
||||
"Failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
|
||||
sta32x->supplies);
|
||||
if (ret != 0) {
|
||||
@ -984,6 +995,9 @@ static void sta32x_remove(struct snd_soc_component *component)
|
||||
|
||||
sta32x_watchdog_stop(sta32x);
|
||||
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
|
||||
|
||||
if (sta32x->xti_clk)
|
||||
clk_disable_unprepare(sta32x->xti_clk);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver sta32x_component = {
|
||||
@ -1041,6 +1055,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
|
||||
of_property_read_u8(np, "st,ch3-output-mapping",
|
||||
&pdata->ch3_output_mapping);
|
||||
|
||||
if (of_get_property(np, "st,fault-detect-recovery", NULL))
|
||||
pdata->fault_detect_recovery = 1;
|
||||
if (of_get_property(np, "st,thermal-warning-recovery", NULL))
|
||||
pdata->thermal_warning_recovery = 1;
|
||||
if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
|
||||
@ -1098,6 +1114,17 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clock */
|
||||
sta32x->xti_clk = devm_clk_get(dev, "xti");
|
||||
if (IS_ERR(sta32x->xti_clk)) {
|
||||
ret = PTR_ERR(sta32x->xti_clk);
|
||||
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
|
||||
sta32x->xti_clk = NULL;
|
||||
}
|
||||
|
||||
/* GPIOs */
|
||||
sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
|
@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int first_slot;
|
||||
int ret;
|
||||
|
||||
@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
if (ret < 0)
|
||||
goto error_snd_soc_component_update_bits;
|
||||
|
||||
/* Configure TDM slot width. This is only applicable to TAS5722. */
|
||||
switch (tas5720->devtype) {
|
||||
case TAS5722:
|
||||
ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
|
||||
TAS5722_TDM_SLOT_16B,
|
||||
slot_width == 16 ?
|
||||
TAS5722_TDM_SLOT_16B : 0);
|
||||
if (ret < 0)
|
||||
goto error_snd_soc_component_update_bits;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_snd_soc_component_update_bits:
|
||||
@ -485,15 +500,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
|
||||
);
|
||||
|
||||
/*
|
||||
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
|
||||
* setting the gain below -100 dB (register value <0x7) is effectively a MUTE
|
||||
* as per device datasheet.
|
||||
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
|
||||
* depending on the device. Note that setting the gain below -100 dB
|
||||
* (register value <0x7) is effectively a MUTE as per device datasheet.
|
||||
*
|
||||
* Note that for the TAS5722 the digital volume controls are actually split
|
||||
* over two registers, so we need custom getters/setters for access.
|
||||
*/
|
||||
static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
|
||||
static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
|
||||
static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
|
||||
|
||||
static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int val;
|
||||
|
||||
snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val);
|
||||
ucontrol->value.integer.value[0] = val << 1;
|
||||
|
||||
snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val);
|
||||
ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
unsigned int sel = ucontrol->value.integer.value[0];
|
||||
|
||||
snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
|
||||
snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
|
||||
TAS5722_VOL_CONTROL_LSB, sel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new tas5720_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
|
||||
TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv),
|
||||
TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
|
||||
TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new tas5722_snd_controls[] = {
|
||||
SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
|
||||
0, 0, 511, 0,
|
||||
tas5722_volume_get, tas5722_volume_set,
|
||||
tas5722_dac_tlv),
|
||||
SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
|
||||
TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
|
||||
};
|
||||
@ -527,6 +583,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
|
||||
.probe = tas5720_codec_probe,
|
||||
.remove = tas5720_codec_remove,
|
||||
.suspend = tas5720_suspend,
|
||||
.resume = tas5720_resume,
|
||||
.controls = tas5722_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tas5722_snd_controls),
|
||||
.dapm_widgets = tas5720_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
|
||||
.dapm_routes = tas5720_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
/* PCM rates supported by the TAS5720 driver */
|
||||
#define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
||||
@ -613,9 +686,23 @@ static int tas5720_probe(struct i2c_client *client,
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
ret = devm_snd_soc_register_component(&client->dev,
|
||||
&soc_component_dev_tas5720,
|
||||
tas5720_dai, ARRAY_SIZE(tas5720_dai));
|
||||
switch (id->driver_data) {
|
||||
case TAS5720:
|
||||
ret = devm_snd_soc_register_component(&client->dev,
|
||||
&soc_component_dev_tas5720,
|
||||
tas5720_dai,
|
||||
ARRAY_SIZE(tas5720_dai));
|
||||
break;
|
||||
case TAS5722:
|
||||
ret = devm_snd_soc_register_component(&client->dev,
|
||||
&soc_component_dev_tas5722,
|
||||
tas5720_dai,
|
||||
ARRAY_SIZE(tas5720_dai));
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unexpected private driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register component: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -41,6 +41,7 @@ struct tas6424_data {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
|
||||
struct delayed_work fault_check_work;
|
||||
unsigned int last_cfault;
|
||||
unsigned int last_fault1;
|
||||
unsigned int last_fault2;
|
||||
unsigned int last_warn;
|
||||
@ -406,9 +407,54 @@ static void tas6424_fault_check_work(struct work_struct *work)
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_CHANNEL_FAULT, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read CHANNEL_FAULT register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!reg) {
|
||||
tas6424->last_cfault = reg;
|
||||
goto check_global_fault1_reg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only flag errors once for a given occurrence. This is needed as
|
||||
* the TAS6424 will take time clearing the fault condition internally
|
||||
* during which we don't want to bombard the system with the same
|
||||
* error message over and over.
|
||||
*/
|
||||
if ((reg & TAS6424_FAULT_OC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH1))
|
||||
dev_crit(dev, "experienced a channel 1 overcurrent fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH2))
|
||||
dev_crit(dev, "experienced a channel 2 overcurrent fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH3))
|
||||
dev_crit(dev, "experienced a channel 3 overcurrent fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_OC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH4))
|
||||
dev_crit(dev, "experienced a channel 4 overcurrent fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_DC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH1))
|
||||
dev_crit(dev, "experienced a channel 1 DC fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_DC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH2))
|
||||
dev_crit(dev, "experienced a channel 2 DC fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_DC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH3))
|
||||
dev_crit(dev, "experienced a channel 3 DC fault\n");
|
||||
|
||||
if ((reg & TAS6424_FAULT_DC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH4))
|
||||
dev_crit(dev, "experienced a channel 4 DC fault\n");
|
||||
|
||||
/* Store current fault1 value so we can detect any changes next time */
|
||||
tas6424->last_cfault = reg;
|
||||
|
||||
check_global_fault1_reg:
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
|
||||
dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -429,12 +475,6 @@ static void tas6424_fault_check_work(struct work_struct *work)
|
||||
goto check_global_fault2_reg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only flag errors once for a given occurrence. This is needed as
|
||||
* the TAS6424 will take time clearing the fault condition internally
|
||||
* during which we don't want to bombard the system with the same
|
||||
* error message over and over.
|
||||
*/
|
||||
if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
|
||||
dev_crit(dev, "experienced a PVDD overvoltage fault\n");
|
||||
|
||||
@ -453,7 +493,7 @@ static void tas6424_fault_check_work(struct work_struct *work)
|
||||
check_global_fault2_reg:
|
||||
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
|
||||
dev_err(dev, "failed to read GLOB_FAULT2 register: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -530,7 +570,7 @@ check_warn_reg:
|
||||
/* Store current warn value so we can detect any changes next time */
|
||||
tas6424->last_warn = reg;
|
||||
|
||||
/* Clear any faults by toggling the CLEAR_FAULT control bit */
|
||||
/* Clear any warnings by toggling the CLEAR_FAULT control bit */
|
||||
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
|
||||
TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
|
||||
if (ret < 0)
|
||||
|
@ -115,6 +115,16 @@
|
||||
#define TAS6424_LDGBYPASS_SHIFT 0
|
||||
#define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT)
|
||||
|
||||
/* TAS6424_GLOB_FAULT1_REG */
|
||||
#define TAS6424_FAULT_OC_CH1 BIT(7)
|
||||
#define TAS6424_FAULT_OC_CH2 BIT(6)
|
||||
#define TAS6424_FAULT_OC_CH3 BIT(5)
|
||||
#define TAS6424_FAULT_OC_CH4 BIT(4)
|
||||
#define TAS6424_FAULT_DC_CH1 BIT(3)
|
||||
#define TAS6424_FAULT_DC_CH2 BIT(2)
|
||||
#define TAS6424_FAULT_DC_CH3 BIT(1)
|
||||
#define TAS6424_FAULT_DC_CH4 BIT(0)
|
||||
|
||||
/* TAS6424_GLOB_FAULT1_REG */
|
||||
#define TAS6424_FAULT_CLOCK BIT(4)
|
||||
#define TAS6424_FAULT_PVDD_OV BIT(3)
|
||||
|
@ -167,6 +167,7 @@ struct aic31xx_priv {
|
||||
u8 p_div;
|
||||
int rate_div_line;
|
||||
bool master_dapm_route_applied;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct aic31xx_rate_divs {
|
||||
@ -1391,6 +1392,69 @@ static const struct acpi_device_id aic31xx_acpi_match[] = {
|
||||
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
|
||||
#endif
|
||||
|
||||
static irqreturn_t aic31xx_irq(int irq, void *data)
|
||||
{
|
||||
struct aic31xx_priv *aic31xx = data;
|
||||
struct device *dev = aic31xx->dev;
|
||||
unsigned int value;
|
||||
bool handled = false;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read interrupt mask: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (value)
|
||||
handled = true;
|
||||
else
|
||||
goto read_overflow;
|
||||
|
||||
if (value & AIC31XX_HPLSCDETECT)
|
||||
dev_err(dev, "Short circuit on Left output is detected\n");
|
||||
if (value & AIC31XX_HPRSCDETECT)
|
||||
dev_err(dev, "Short circuit on Right output is detected\n");
|
||||
if (value & ~(AIC31XX_HPLSCDETECT |
|
||||
AIC31XX_HPRSCDETECT))
|
||||
dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
|
||||
|
||||
read_overflow:
|
||||
ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read overflow flag: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (value)
|
||||
handled = true;
|
||||
else
|
||||
goto exit;
|
||||
|
||||
if (value & AIC31XX_DAC_OF_LEFT)
|
||||
dev_warn(dev, "Left-channel DAC overflow has occurred\n");
|
||||
if (value & AIC31XX_DAC_OF_RIGHT)
|
||||
dev_warn(dev, "Right-channel DAC overflow has occurred\n");
|
||||
if (value & AIC31XX_DAC_OF_SHIFTER)
|
||||
dev_warn(dev, "DAC barrel shifter overflow has occurred\n");
|
||||
if (value & AIC31XX_ADC_OF)
|
||||
dev_warn(dev, "ADC overflow has occurred\n");
|
||||
if (value & AIC31XX_ADC_OF_SHIFTER)
|
||||
dev_warn(dev, "ADC barrel shifter overflow has occurred\n");
|
||||
if (value & ~(AIC31XX_DAC_OF_LEFT |
|
||||
AIC31XX_DAC_OF_RIGHT |
|
||||
AIC31XX_DAC_OF_SHIFTER |
|
||||
AIC31XX_ADC_OF |
|
||||
AIC31XX_ADC_OF_SHIFTER))
|
||||
dev_warn(dev, "Unknown overflow interrupt flags: 0x%08x\n", value);
|
||||
|
||||
exit:
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -1413,6 +1477,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
aic31xx->dev = &i2c->dev;
|
||||
aic31xx->irq = i2c->irq;
|
||||
|
||||
aic31xx->codec_type = id->driver_data;
|
||||
|
||||
@ -1456,6 +1521,26 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (aic31xx->irq > 0) {
|
||||
regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1,
|
||||
AIC31XX_GPIO1_FUNC_MASK,
|
||||
AIC31XX_GPIO1_INT1 <<
|
||||
AIC31XX_GPIO1_FUNC_SHIFT);
|
||||
|
||||
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
|
||||
AIC31XX_SC |
|
||||
AIC31XX_ENGINE);
|
||||
|
||||
ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
|
||||
NULL, aic31xx_irq,
|
||||
IRQF_ONESHOT, "aic31xx-irq",
|
||||
aic31xx);
|
||||
if (ret) {
|
||||
dev_err(aic31xx->dev, "Unable to request IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (aic31xx->codec_type & DAC31XX_BIT)
|
||||
return devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_codec_driver_aic31xx,
|
||||
|
@ -173,6 +173,13 @@ struct aic31xx_pdata {
|
||||
#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
|
||||
#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
|
||||
|
||||
/* AIC31XX_OFFLAG */
|
||||
#define AIC31XX_DAC_OF_LEFT BIT(7)
|
||||
#define AIC31XX_DAC_OF_RIGHT BIT(6)
|
||||
#define AIC31XX_DAC_OF_SHIFTER BIT(5)
|
||||
#define AIC31XX_ADC_OF BIT(3)
|
||||
#define AIC31XX_ADC_OF_SHIFTER BIT(1)
|
||||
|
||||
/* AIC31XX_INTRDACFLAG */
|
||||
#define AIC31XX_HPLSCDETECT BIT(7)
|
||||
#define AIC31XX_HPRSCDETECT BIT(6)
|
||||
@ -191,6 +198,22 @@ struct aic31xx_pdata {
|
||||
#define AIC31XX_SC BIT(3)
|
||||
#define AIC31XX_ENGINE BIT(2)
|
||||
|
||||
/* AIC31XX_GPIO1 */
|
||||
#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2)
|
||||
#define AIC31XX_GPIO1_FUNC_SHIFT 2
|
||||
#define AIC31XX_GPIO1_DISABLED 0x00
|
||||
#define AIC31XX_GPIO1_INPUT 0x01
|
||||
#define AIC31XX_GPIO1_GPI 0x02
|
||||
#define AIC31XX_GPIO1_GPO 0x03
|
||||
#define AIC31XX_GPIO1_CLKOUT 0x04
|
||||
#define AIC31XX_GPIO1_INT1 0x05
|
||||
#define AIC31XX_GPIO1_INT2 0x06
|
||||
#define AIC31XX_GPIO1_ADC_WCLK 0x07
|
||||
#define AIC31XX_GPIO1_SBCLK 0x08
|
||||
#define AIC31XX_GPIO1_SWCLK 0x09
|
||||
#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10
|
||||
#define AIC31XX_GPIO1_SDOUT 0x11
|
||||
|
||||
/* AIC31XX_DACSETUP */
|
||||
#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
|
||||
|
||||
|
@ -3459,7 +3459,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c,
|
||||
/* Sync pg sel reg with cache */
|
||||
regmap_write(tscs454->regmap, R_PAGESEL, 0x00);
|
||||
|
||||
ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
|
||||
ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
|
||||
tscs454_dais, ARRAY_SIZE(tscs454_dais));
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to register component (%d)\n", ret);
|
||||
|
@ -88,19 +88,6 @@ static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
|
||||
return regmap_write(wm2000->regmap, reg, value);
|
||||
}
|
||||
|
||||
static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r)
|
||||
{
|
||||
struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(wm2000->regmap, r, &val);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void wm2000_reset(struct wm2000_priv *wm2000)
|
||||
{
|
||||
struct i2c_client *i2c = wm2000->i2c;
|
||||
@ -115,14 +102,15 @@ static void wm2000_reset(struct wm2000_priv *wm2000)
|
||||
static int wm2000_poll_bit(struct i2c_client *i2c,
|
||||
unsigned int reg, u8 mask)
|
||||
{
|
||||
struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
|
||||
int timeout = 4000;
|
||||
int val;
|
||||
unsigned int val;
|
||||
|
||||
val = wm2000_read(i2c, reg);
|
||||
regmap_read(wm2000->regmap, reg, &val);
|
||||
|
||||
while (!(val & mask) && --timeout) {
|
||||
msleep(1);
|
||||
val = wm2000_read(i2c, reg);
|
||||
regmap_read(wm2000->regmap, reg, &val);
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
@ -135,6 +123,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
|
||||
{
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
|
||||
unsigned long rate;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(wm2000->anc_mode != ANC_OFF))
|
||||
@ -213,12 +202,17 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
|
||||
WM2000_MODE_THERMAL_ENABLE);
|
||||
}
|
||||
|
||||
ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
|
||||
ret = regmap_read(wm2000->regmap, WM2000_REG_SPEECH_CLARITY, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Unable to read Speech Clarity: %d\n", ret);
|
||||
regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
|
||||
return ret;
|
||||
}
|
||||
if (wm2000->speech_clarity)
|
||||
ret |= WM2000_SPEECH_CLARITY;
|
||||
val |= WM2000_SPEECH_CLARITY;
|
||||
else
|
||||
ret &= ~WM2000_SPEECH_CLARITY;
|
||||
wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
|
||||
val &= ~WM2000_SPEECH_CLARITY;
|
||||
wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, val);
|
||||
|
||||
wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
|
||||
wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02);
|
||||
@ -824,7 +818,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
||||
const char *filename;
|
||||
const struct firmware *fw = NULL;
|
||||
int ret, i;
|
||||
int reg;
|
||||
unsigned int reg;
|
||||
u16 id;
|
||||
|
||||
wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL);
|
||||
@ -860,9 +854,17 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
|
||||
/* Verify that this is a WM2000 */
|
||||
reg = wm2000_read(i2c, WM2000_REG_ID1);
|
||||
ret = regmap_read(wm2000->regmap, WM2000_REG_ID1, ®);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Unable to read ID1: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
id = reg << 8;
|
||||
reg = wm2000_read(i2c, WM2000_REG_ID2);
|
||||
ret = regmap_read(wm2000->regmap, WM2000_REG_ID2, ®);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Unable to read ID2: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
id |= reg & 0xff;
|
||||
|
||||
if (id != 0x2000) {
|
||||
@ -871,7 +873,11 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
reg = wm2000_read(i2c, WM2000_REG_REVISON);
|
||||
ret = regmap_read(wm2000->regmap, WM2000_REG_REVISON, ®);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Unable to read Revision: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
dev_info(&i2c->dev, "revision %c\n", reg + 'A');
|
||||
|
||||
wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK");
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
@ -50,7 +51,51 @@ static struct snd_soc_dai_driver wm8782_dai = {
|
||||
},
|
||||
};
|
||||
|
||||
/* regulator power supply names */
|
||||
static const char *supply_names[] = {
|
||||
"Vdda", /* analog supply, 2.7V - 3.6V */
|
||||
"Vdd", /* digital supply, 2.7V - 5.5V */
|
||||
};
|
||||
|
||||
struct wm8782_priv {
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
||||
};
|
||||
|
||||
static int wm8782_soc_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
}
|
||||
|
||||
static void wm8782_soc_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm8782_soc_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8782_soc_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm8782_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
|
||||
}
|
||||
#else
|
||||
#define wm8782_soc_suspend NULL
|
||||
#define wm8782_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
|
||||
.probe = wm8782_soc_probe,
|
||||
.remove = wm8782_soc_remove,
|
||||
.suspend = wm8782_soc_suspend,
|
||||
.resume = wm8782_soc_resume,
|
||||
.dapm_widgets = wm8782_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets),
|
||||
.dapm_routes = wm8782_dapm_routes,
|
||||
@ -63,6 +108,24 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
|
||||
|
||||
static int wm8782_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct wm8782_priv *priv;
|
||||
int ret, i;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&soc_component_dev_wm8782, &wm8782_dai, 1);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
|
@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user