Commit b821d298 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/inte' into asoc-next

parents 254d96be 478b7746
...@@ -10,6 +10,8 @@ see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt ...@@ -10,6 +10,8 @@ see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
Below are same as Simple-Card. Below are same as Simple-Card.
- label - label
- widgets
- routing
- dai-format - dai-format
- frame-master - frame-master
- bitclock-master - bitclock-master
...@@ -24,6 +26,9 @@ Required properties: ...@@ -24,6 +26,9 @@ Required properties:
- compatible : "audio-graph-card"; - compatible : "audio-graph-card";
- dais : list of CPU DAI port{s} - dais : list of CPU DAI port{s}
Optional properties:
- pa-gpios: GPIO used to control external amplifier.
Example: Single DAI case Example: Single DAI case
sound_card { sound_card {
......
...@@ -90,9 +90,12 @@ Example 2. 2 CPU 1 Codec (Mixing) ...@@ -90,9 +90,12 @@ Example 2. 2 CPU 1 Codec (Mixing)
... ...
port { port {
codec_endpoint: endpoint { codec_endpoint0: endpoint {
remote-endpoint = <&cpu_endpoint0>; remote-endpoint = <&cpu_endpoint0>;
}; };
codec_endpoint1: endpoint {
remote-endpoint = <&cpu_endpoint1>;
};
}; };
}; };
...@@ -101,7 +104,7 @@ Example 2. 2 CPU 1 Codec (Mixing) ...@@ -101,7 +104,7 @@ Example 2. 2 CPU 1 Codec (Mixing)
ports { ports {
cpu_port0: port { cpu_port0: port {
cpu_endpoint0: endpoint { cpu_endpoint0: endpoint {
remote-endpoint = <&codec_endpoint>; remote-endpoint = <&codec_endpoint0>;
dai-format = "left_j"; dai-format = "left_j";
... ...
...@@ -109,6 +112,8 @@ Example 2. 2 CPU 1 Codec (Mixing) ...@@ -109,6 +112,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
}; };
cpu_port1: port { cpu_port1: port {
cpu_endpoint1: endpoint { cpu_endpoint1: endpoint {
remote-endpoint = <&codec_endpoint1>;
dai-format = "left_j"; dai-format = "left_j";
... ...
}; };
......
...@@ -69,6 +69,8 @@ Optional properties: ...@@ -69,6 +69,8 @@ Optional properties:
- nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,crosstalk-bypass: make crosstalk function bypass if set.
- clocks: list of phandle and clock specifier pairs according to common clock bindings for the - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
clocks described in clock-names clocks described in clock-names
- clock-names: should include "mclk" for the MCLK master clock - clock-names: should include "mclk" for the MCLK master clock
...@@ -96,6 +98,7 @@ Example: ...@@ -96,6 +98,7 @@ Example:
nuvoton,short-key-debounce = <2>; nuvoton,short-key-debounce = <2>;
nuvoton,jack-insert-debounce = <7>; nuvoton,jack-insert-debounce = <7>;
nuvoton,jack-eject-debounce = <7>; nuvoton,jack-eject-debounce = <7>;
nuvoton,crosstalk-bypass;
clock-names = "mclk"; clock-names = "mclk";
clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>; clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
......
* Rockchip PDM controller
Required properties:
- compatible: "rockchip,pdm"
- reg: physical base address of the controller and length of memory mapped
region.
- dmas: DMA specifiers for rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: should include "rx".
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
- clock-names: should contain following:
- "pdm_hclk": clock for PDM BUS
- "pdm_clk" : clock for PDM controller
- pinctrl-names: Must contain a "default" entry.
- pinctrl-N: One property must exist for each entry in
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
for details of the property values.
Example for rk3328 PDM controller:
pdm: pdm@ff040000 {
compatible = "rockchip,pdm";
reg = <0x0 0xff040000 0x0 0x1000>;
clocks = <&clk_pdm>, <&clk_gates28 0>;
clock-names = "pdm_clk", "pdm_hclk";
dmas = <&pdma 16>;
#dma-cells = <1>;
dma-names = "rx";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pdmm0_clk
&pdmm0_fsync
&pdmm0_sdi0
&pdmm0_sdi1
&pdmm0_sdi2
&pdmm0_sdi3>;
pinctrl-1 = <&pdmm0_sleep>;
status = "disabled";
};
...@@ -9,7 +9,9 @@ Required properties: ...@@ -9,7 +9,9 @@ Required properties:
- compatible: should be one of the following: - compatible: should be one of the following:
- "rockchip,rk3066-spdif" - "rockchip,rk3066-spdif"
- "rockchip,rk3188-spdif" - "rockchip,rk3188-spdif"
- "rockchip,rk3228-spdif"
- "rockchip,rk3288-spdif" - "rockchip,rk3288-spdif"
- "rockchip,rk3328-spdif"
- "rockchip,rk3366-spdif" - "rockchip,rk3366-spdif"
- "rockchip,rk3368-spdif" - "rockchip,rk3368-spdif"
- "rockchip,rk3399-spdif" - "rockchip,rk3399-spdif"
......
...@@ -5,11 +5,6 @@ Required properties: ...@@ -5,11 +5,6 @@ Required properties:
- compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board, - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
"samsung,odroidxu4-audio" - for Odroid XU4 board "samsung,odroidxu4-audio" - for Odroid XU4 board
- model - the user-visible name of this sound complex - model - the user-visible name of this sound complex
- 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
controller
- 'codec' subnode with a 'sound-dai' property containing list of phandles
to the CODEC nodes, first entry must be corresponding to the MAX98090
CODEC and the second entry must be the phandle of the HDMI IP block node
- clocks - should contain entries matching clock names in the clock-names - clocks - should contain entries matching clock names in the clock-names
property property
- clock-names - should contain following entries: - clock-names - should contain following entries:
...@@ -32,12 +27,18 @@ Required properties: ...@@ -32,12 +27,18 @@ Required properties:
For Odroid XU4: For Odroid XU4:
no entries no entries
Required sub-nodes:
- 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
controller
- 'codec' subnode with a 'sound-dai' property containing list of phandles
to the CODEC nodes, first entry must be corresponding to the MAX98090
CODEC and the second entry must be the phandle of the HDMI IP block node
Example: Example:
sound { sound {
compatible = "samsung,odroidxu3-audio"; compatible = "samsung,odroidxu3-audio";
samsung,cpu-dai = <&i2s0>;
samsung,codec-dai = <&max98090>;
model = "Odroid-XU3"; model = "Odroid-XU3";
samsung,audio-routing = samsung,audio-routing =
"Headphone Jack", "HPL", "Headphone Jack", "HPL",
......
STMicroelectronics STM32 SPI/I2S Controller
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
Only some SPI instances support I2S.
Required properties:
- compatible: Must be "st,stm32h7-i2s"
- reg: Offset and length of the device's register set.
- interrupts: Must contain the interrupt line id.
- clocks: Must contain phandle and clock specifier pairs for each entry
in clock-names.
- clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k".
"i2sclk": clock which feeds the internal clock generator
"pclk": clock which feeds the peripheral bus interface
"x8k": I2S parent clock for sampling rates multiple of 8kHz.
"x11k": I2S parent clock for sampling rates multiple of 11.025kHz.
- dmas: DMA specifiers for tx and rx dma.
See Documentation/devicetree/bindings/dma/stm32-dma.txt.
- dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
- pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
Optional properties:
- resets: Reference to a reset controller asserting the reset controller
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
sound_card {
compatible = "audio-graph-card";
dais = <&i2s2_port>;
};
i2s2: audio-controller@40003800 {
compatible = "st,stm32h7-i2s";
reg = <0x40003800 0x400>;
interrupts = <36>;
clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
clock-names = "pclk", "i2sclk", "x8k", "x11k";
dmas = <&dmamux2 2 39 0x400 0x1>,
<&dmamux2 3 40 0x400 0x1>;
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s2>;
i2s2_port: port@0 {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
format = "i2s";
};
};
};
audio-codec {
codec_port: port@0 {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
...@@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has ...@@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has
its own clock generator and I/O lines controller. its own clock generator and I/O lines controller.
Required properties: Required properties:
- compatible: Should be "st,stm32f4-sai" - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai"
- reg: Base address and size of SAI common register set. - reg: Base address and size of SAI common register set.
- clocks: Must contain phandle and clock specifier pairs for each entry - clocks: Must contain phandle and clock specifier pairs for each entry
in clock-names. in clock-names.
...@@ -36,6 +36,10 @@ SAI subnodes required properties: ...@@ -36,6 +36,10 @@ SAI subnodes required properties:
- pinctrl-names: should contain only value "default" - pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example: Example:
sound_card { sound_card {
compatible = "audio-graph-card"; compatible = "audio-graph-card";
...@@ -43,38 +47,29 @@ sound_card { ...@@ -43,38 +47,29 @@ sound_card {
}; };
sai1: sai1@40015800 { sai1: sai1@40015800 {
compatible = "st,stm32f4-sai"; compatible = "st,stm32h7-sai";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
ranges; ranges = <0 0x40015800 0x400>;
reg = <0x40015800 0x4>; reg = <0x40015800 0x4>;
clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>; clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
clock-names = "x8k", "x11k"; clock-names = "x8k", "x11k";
interrupts = <87>; interrupts = <87>;
sai1b: audio-controller@40015824 { sai1a: audio-controller@40015804 {
#sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-a";
compatible = "st,stm32-sai-sub-b"; reg = <0x4 0x1C>;
reg = <0x40015824 0x1C>; clocks = <&rcc SAI1_CK>;
clocks = <&rcc 1 CLK_SAI2>;
clock-names = "sai_ck"; clock-names = "sai_ck";
dmas = <&dma2 5 0 0x400 0x0>; dmas = <&dmamux1 1 87 0x400 0x0>;
dma-names = "tx"; dma-names = "tx";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai1b>; pinctrl-0 = <&pinctrl_sai1a>;
ports {
#address-cells = <1>;
#size-cells = <0>;
sai1b_port: port@0 { sai1b_port: port {
reg = <0>; cpu_endpoint: endpoint {
cpu_endpoint: endpoint { remote-endpoint = <&codec_endpoint>;
remote-endpoint = <&codec_endpoint>; format = "i2s";
audio-graph-card,format = "i2s";
audio-graph-card,bitclock-master = <&codec_endpoint>;
audio-graph-card,frame-master = <&codec_endpoint>;
};
}; };
}; };
}; };
......
STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
IEC-60958 and IEC-61937.
Required properties:
- compatible: should be "st,stm32h7-spdifrx"
- reg: cpu DAI IP base address and size
- clocks: must contain an entry for kclk (used as S/PDIF signal reference)
- clock-names: must contain "kclk"
- interrupts: cpu DAI interrupt line
- dmas: DMA specifiers for audio data DMA and iec control flow DMA
See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
- dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
Optional properties:
- resets: Reference to a reset controller asserting the SPDIFRX
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
spdifrx: spdifrx@40004000 {
compatible = "st,stm32h7-spdifrx";
reg = <0x40004000 0x400>;
clocks = <&rcc SPDIFRX_CK>;
clock-names = "kclk";
interrupts = <97>;
dmas = <&dmamux1 2 93 0x400 0x0>,
<&dmamux1 3 94 0x400 0x0>;
dma-names = "rx", "rx-ctrl";
pinctrl-0 = <&spdifrx_pins>;
pinctrl-names = "default";
spdifrx_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
};
};
};
spdif_in: spdif-in {
compatible = "linux,spdif-dir";
codec_port: port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
soundcard {
compatible = "audio-graph-card";
dais = <&spdifrx_port>;
};
...@@ -7,6 +7,7 @@ Required properties: ...@@ -7,6 +7,7 @@ Required properties:
- "allwinner,sun7i-a20-codec" - "allwinner,sun7i-a20-codec"
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- reg: must contain the registers location and length - reg: must contain the registers location and length
- interrupts: must contain the codec interrupt - interrupts: must contain the codec interrupt
- dmas: DMA channels for tx and rx dma. See the DMA client binding, - dmas: DMA channels for tx and rx dma. See the DMA client binding,
...@@ -25,6 +26,7 @@ Required properties for the following compatibles: ...@@ -25,6 +26,7 @@ Required properties for the following compatibles:
- "allwinner,sun6i-a31-codec" - "allwinner,sun6i-a31-codec"
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- resets: phandle to the reset control for this device - resets: phandle to the reset control for this device
- allwinner,audio-routing: A list of the connections between audio components. - allwinner,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the Each entry is a pair of strings, the first being the
...@@ -34,15 +36,15 @@ Required properties for the following compatibles: ...@@ -34,15 +36,15 @@ Required properties for the following compatibles:
Audio pins on the SoC: Audio pins on the SoC:
"HP" "HP"
"HPCOM" "HPCOM"
"LINEIN" "LINEIN" (not on sun8i-v3s)
"LINEOUT" (not on sun8i-a23) "LINEOUT" (not on sun8i-a23 or sun8i-v3s)
"MIC1" "MIC1"
"MIC2" "MIC2" (not on sun8i-v3s)
"MIC3" (sun6i-a31 only) "MIC3" (sun6i-a31 only)
Microphone biases from the SoC: Microphone biases from the SoC:
"HBIAS" "HBIAS"
"MBIAS" "MBIAS" (not on sun8i-v3s)
Board connectors: Board connectors:
"Headphone" "Headphone"
...@@ -55,6 +57,7 @@ Required properties for the following compatibles: ...@@ -55,6 +57,7 @@ Required properties for the following compatibles:
Required properties for the following compatibles: Required properties for the following compatibles:
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- allwinner,codec-analog-controls: A phandle to the codec analog controls - allwinner,codec-analog-controls: A phandle to the codec analog controls
block in the PRCM. block in the PRCM.
......
...@@ -4,6 +4,7 @@ Required properties: ...@@ -4,6 +4,7 @@ Required properties:
- compatible: must be one of the following compatibles: - compatible: must be one of the following compatibles:
- "allwinner,sun8i-a23-codec-analog" - "allwinner,sun8i-a23-codec-analog"
- "allwinner,sun8i-h3-codec-analog" - "allwinner,sun8i-h3-codec-analog"
- "allwinner,sun8i-v3s-codec-analog"
Required properties if not a sub-node of the PRCM node: Required properties if not a sub-node of the PRCM node:
- reg: must contain the registers location and length - reg: must contain the registers location and length
......
ZTE ZX AUD96P22 Audio Codec
Required properties:
- compatible: Must be "zte,zx-aud96p22"
- #sound-dai-cells: Should be 0
- reg: I2C bus slave address of AUD96P22
Example:
i2c0: i2c@1486000 {
compatible = "zte,zx296718-i2c";
reg = <0x01486000 0x1000>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&audiocrm AUDIO_I2C0_WCLK>;
clock-frequency = <1600000>;
aud96p22: codec@22 {
compatible = "zte,zx-aud96p22";
#sound-dai-cells = <0>;
reg = <0x22>;
};
};
...@@ -18,9 +18,11 @@ ...@@ -18,9 +18,11 @@
#ifndef __HDMI_CODEC_H__ #ifndef __HDMI_CODEC_H__
#define __HDMI_CODEC_H__ #define __HDMI_CODEC_H__
#include <linux/of_graph.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
#include <sound/soc.h>
#include <uapi/sound/asound.h> #include <uapi/sound/asound.h>
/* /*
...@@ -87,6 +89,13 @@ struct hdmi_codec_ops { ...@@ -87,6 +89,13 @@ struct hdmi_codec_ops {
*/ */
int (*get_eld)(struct device *dev, void *data, int (*get_eld)(struct device *dev, void *data,
uint8_t *buf, size_t len); uint8_t *buf, size_t len);
/*
* Getting DAI ID
* Optional
*/
int (*get_dai_id)(struct snd_soc_component *comment,
struct device_node *endpoint);
}; };
/* HDMI codec initalization data */ /* HDMI codec initalization data */
......
...@@ -21,8 +21,10 @@ struct rt5645_platform_data { ...@@ -21,8 +21,10 @@ struct rt5645_platform_data {
/* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
unsigned int jd_mode; unsigned int jd_mode;
/* Invert JD when jack insert */ /* Use level triggered irq */
bool jd_invert; bool level_trigger_irq;
/* Invert JD1_1 status polarity */
bool inv_jd1_1;
}; };
#endif #endif
...@@ -22,6 +22,11 @@ struct asoc_simple_dai { ...@@ -22,6 +22,11 @@ struct asoc_simple_dai {
struct clk *clk; struct clk *clk;
}; };
struct asoc_simple_card_data {
u32 convert_rate;
u32 convert_channels;
};
int asoc_simple_card_parse_daifmt(struct device *dev, int asoc_simple_card_parse_daifmt(struct device *dev,
struct device_node *node, struct device_node *node,
struct device_node *codec, struct device_node *codec,
...@@ -45,6 +50,8 @@ int asoc_simple_card_parse_clk(struct device *dev, ...@@ -45,6 +50,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *dai_of_node, struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai, struct asoc_simple_dai *simple_dai,
const char *name); const char *name);
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, \ #define asoc_simple_card_parse_cpu(node, dai_link, \
list_name, cells_name, is_single_link) \ list_name, cells_name, is_single_link) \
...@@ -73,6 +80,12 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, ...@@ -73,6 +80,12 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
struct device_node **endpoint_np, struct device_node **endpoint_np,
const char **dai_name); const char **dai_name);
#define asoc_simple_card_of_parse_tdm(np, dai) \
snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \
&(dai)->rx_slot_mask, \
&(dai)->slots, \
&(dai)->slot_width);
int asoc_simple_card_init_dai(struct snd_soc_dai *dai, int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
struct asoc_simple_dai *simple_dai); struct asoc_simple_dai *simple_dai);
...@@ -82,4 +95,15 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, ...@@ -82,4 +95,15 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
int asoc_simple_card_clean_reference(struct snd_soc_card *card); int asoc_simple_card_clean_reference(struct snd_soc_card *card);
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
struct snd_pcm_hw_params *params);
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
struct asoc_simple_card_data *data);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
char *prefix,
int optional);
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
char *prefix);
#endif /* __SIMPLE_CARD_UTILS_H */ #endif /* __SIMPLE_CARD_UTILS_H */
...@@ -28,6 +28,8 @@ struct snd_soc_component; ...@@ -28,6 +28,8 @@ struct snd_soc_component;
struct snd_soc_tplg_pcm_fe; struct snd_soc_tplg_pcm_fe;
struct snd_soc_dapm_context; struct snd_soc_dapm_context;
struct snd_soc_card; struct snd_soc_card;
struct snd_kcontrol_new;
struct snd_soc_dai_link;
/* object scan be loaded and unloaded in groups with identfying indexes */ /* object scan be loaded and unloaded in groups with identfying indexes */
#define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */ #define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */
...@@ -116,6 +118,9 @@ struct snd_soc_tplg_ops { ...@@ -116,6 +118,9 @@ struct snd_soc_tplg_ops {
int (*widget_load)(struct snd_soc_component *, int (*widget_load)(struct snd_soc_component *,
struct snd_soc_dapm_widget *, struct snd_soc_dapm_widget *,
struct snd_soc_tplg_dapm_widget *); struct snd_soc_tplg_dapm_widget *);
int (*widget_ready)(struct snd_soc_component *,
struct snd_soc_dapm_widget *,
struct snd_soc_tplg_dapm_widget *);
int (*widget_unload)(struct snd_soc_component *, int (*widget_unload)(struct snd_soc_component *,
struct snd_soc_dobj *); struct snd_soc_dobj *);
......
...@@ -1119,6 +1119,11 @@ config SND_SOC_WM9713 ...@@ -1119,6 +1119,11 @@ config SND_SOC_WM9713
tristate tristate
select REGMAP_AC97 select REGMAP_AC97
config SND_SOC_ZX_AUD96P22
tristate "ZTE ZX AUD96P22 CODEC"
depends on I2C
select REGMAP_I2C
# Amp # Amp
config SND_SOC_LM4857 config SND_SOC_LM4857
tristate tristate
......
...@@ -225,6 +225,7 @@ snd-soc-wm9705-objs := wm9705.o ...@@ -225,6 +225,7 @@ snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-zx-aud96p22-objs := zx_aud96p22.o
# Amp # Amp
snd-soc-dio2125-objs := dio2125.o snd-soc-dio2125-objs := dio2125.o
snd-soc-max9877-objs := max9877.o snd-soc-max9877-objs := max9877.o
...@@ -457,6 +458,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o ...@@ -457,6 +458,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
# Amp # Amp
obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o
......
...@@ -25,17 +25,6 @@ ...@@ -25,17 +25,6 @@
#include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */ #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
struct hdmi_device {
struct device *dev;
struct list_head list;
int cnt;
};
#define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list)
LIST_HEAD(hdmi_device_list);
static DEFINE_MUTEX(hdmi_mutex);
#define DAI_NAME_SIZE 16
#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
struct hdmi_codec_channel_map_table { struct hdmi_codec_channel_map_table {
...@@ -293,7 +282,6 @@ struct hdmi_codec_priv { ...@@ -293,7 +282,6 @@ struct hdmi_codec_priv {
struct hdmi_codec_daifmt daifmt[2]; struct hdmi_codec_daifmt daifmt[2];
struct mutex current_stream_lock; struct mutex current_stream_lock;
struct snd_pcm_substream *current_stream; struct snd_pcm_substream *current_stream;
struct snd_pcm_hw_constraint_list ratec;
uint8_t eld[MAX_ELD_BYTES]; uint8_t eld[MAX_ELD_BYTES];
struct snd_pcm_chmap *chmap_info; struct snd_pcm_chmap *chmap_info;
unsigned int chmap_idx; unsigned int chmap_idx;
...@@ -702,6 +690,7 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, ...@@ -702,6 +690,7 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
} }
static struct snd_soc_dai_driver hdmi_i2s_dai = { static struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S, .id = DAI_ID_I2S,
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
...@@ -716,6 +705,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = { ...@@ -716,6 +705,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
}; };
static const struct snd_soc_dai_driver hdmi_spdif_dai = { static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF, .id = DAI_ID_SPDIF,
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
...@@ -728,30 +718,16 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { ...@@ -728,30 +718,16 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.pcm_new = hdmi_codec_pcm_new, .pcm_new = hdmi_codec_pcm_new,
}; };
static char hdmi_dai_name[][DAI_NAME_SIZE] = { static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
"hdmi-hifi.0", struct device_node *endpoint)
"hdmi-hifi.1",
"hdmi-hifi.2",
"hdmi-hifi.3",
};
static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
struct of_phandle_args *args,
const char **dai_name)
{ {
int id; struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */
if (args->args_count) if (hcp->hcd.ops->get_dai_id)
id = args->args[0]; ret = hcp->hcd.ops->get_dai_id(component, endpoint);
else
id = 0;
if (id < ARRAY_SIZE(hdmi_dai_name)) { return ret;
*dai_name = hdmi_dai_name[id];
return 0;
}
return -EAGAIN;
} }
static struct snd_soc_codec_driver hdmi_codec = { static struct snd_soc_codec_driver hdmi_codec = {
...@@ -762,7 +738,7 @@ static struct snd_soc_codec_driver hdmi_codec = { ...@@ -762,7 +738,7 @@ static struct snd_soc_codec_driver hdmi_codec = {
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
.dapm_routes = hdmi_routes, .dapm_routes = hdmi_routes,
.num_dapm_routes = ARRAY_SIZE(hdmi_routes), .num_dapm_routes = ARRAY_SIZE(hdmi_routes),
.of_xlate_dai_name = hdmi_of_xlate_dai_name, .of_xlate_dai_id = hdmi_of_xlate_dai_id,
}, },
}; };
...@@ -771,8 +747,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) ...@@ -771,8 +747,6 @@ static int hdmi_codec_probe(struct platform_device *pdev)
struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct hdmi_codec_priv *hcp; struct hdmi_codec_priv *hcp;
struct hdmi_device *hd;
struct list_head *pos;
int dai_count, i = 0; int dai_count, i = 0;
int ret; int ret;
...@@ -794,35 +768,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) ...@@ -794,35 +768,6 @@ static int hdmi_codec_probe(struct platform_device *pdev)
if (!hcp) if (!hcp)
return -ENOMEM; return -ENOMEM;
hd = NULL;
mutex_lock(&hdmi_mutex);
list_for_each(pos, &hdmi_device_list) {
struct hdmi_device *tmp = pos_to_hdmi_device(pos);
if (tmp->dev == dev->parent) {
hd = tmp;
break;
}
}
if (!hd) {
hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
if (!hd) {
mutex_unlock(&hdmi_mutex);
return -ENOMEM;
}
hd->dev = dev->parent;
list_add_tail(&hd->list, &hdmi_device_list);
}
mutex_unlock(&hdmi_mutex);
if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
dev_err(dev, "too many hdmi codec are deteced\n");
return -EINVAL;
}
hcp->hcd = *hcd; hcp->hcd = *hcd;
mutex_init(&hcp->current_stream_lock); mutex_init(&hcp->current_stream_lock);
...@@ -835,14 +780,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) ...@@ -835,14 +780,11 @@ static int hdmi_codec_probe(struct platform_device *pdev)
hcp->daidrv[i] = hdmi_i2s_dai; hcp->daidrv[i] = hdmi_i2s_dai;
hcp->daidrv[i].playback.channels_max = hcp->daidrv[i].playback.channels_max =
hcd->max_i2s_channels; hcd->max_i2s_channels;
hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
i++; i++;
} }
if (hcd->spdif) { if (hcd->spdif)
hcp->daidrv[i] = hdmi_spdif_dai; hcp->daidrv[i] = hdmi_spdif_dai;
hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
}
ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv, ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
dai_count); dai_count);
...@@ -859,20 +801,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) ...@@ -859,20 +801,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
static int hdmi_codec_remove(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct list_head *pos;
struct hdmi_codec_priv *hcp; struct hdmi_codec_priv *hcp;
mutex_lock(&hdmi_mutex);
list_for_each(pos, &hdmi_device_list) {
struct hdmi_device *tmp = pos_to_hdmi_device(pos);
if (tmp->dev == dev->parent) {
list_del(pos);
break;
}
}
mutex_unlock(&hdmi_mutex);
hcp = dev_get_drvdata(dev); hcp = dev_get_drvdata(dev);
kfree(hcp->chmap_info); kfree(hcp->chmap_info);
snd_soc_unregister_codec(dev); snd_soc_unregister_codec(dev);
......
...@@ -132,7 +132,7 @@ enum rates { ...@@ -132,7 +132,7 @@ enum rates {
pcm_rate_48, max_pcm_rate, pcm_rate_48, max_pcm_rate,
}; };
struct ni_div_rates { static const struct ni_div_rates {
u32 mclk; u32 mclk;
u16 ni[max_pcm_rate]; u16 ni[max_pcm_rate];
} ni_div[] = { } ni_div[] = {
......
...@@ -223,8 +223,8 @@ struct pm8916_wcd_analog_priv { ...@@ -223,8 +223,8 @@ struct pm8916_wcd_analog_priv {
u16 codec_version; u16 codec_version;
struct clk *mclk; struct clk *mclk;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
bool micbias1_cap_mode; unsigned int micbias1_cap_mode;
bool micbias2_cap_mode; unsigned int micbias2_cap_mode;
}; };
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
...@@ -285,7 +285,7 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) ...@@ -285,7 +285,7 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
*codec, int event, *codec, int event,
int reg, u32 cap_mode) int reg, unsigned int cap_mode)
{ {
switch (event) { switch (event) {
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
......
...@@ -1124,6 +1124,57 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -1124,6 +1124,57 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0; return 0;
} }
/**
* nau8824_set_tdm_slot - configure DAI TDM.
* @dai: DAI
* @tx_mask: Bitmask representing active TX slots. Ex.
* 0xf for normal 4 channel TDM.
* 0xf0 for shifted 4 channel TDM
* @rx_mask: Bitmask [0:1] representing active DACR RX slots.
* Bitmask [2:3] representing active DACL RX slots.
* 00=CH0,01=CH1,10=CH2,11=CH3. Ex.
* 0xf for DACL/R selecting TDM CH3.
* 0xf0 for DACL/R selecting shifted TDM CH3.
* @slots: Number of slots in use.
* @slot_width: Width in bits for each slot.
*
* Configures a DAI for TDM operation. Only support 4 slots TDM.
*/
static int nau8824_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_codec *codec = dai->codec;
struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
unsigned int tslot_l = 0, ctrl_val = 0;
if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) ||
((rx_mask & 0xf0) && (rx_mask & 0xf)) ||
((rx_mask & 0xf0) && (tx_mask & 0xf)) ||
((rx_mask & 0xf) && (tx_mask & 0xf0)))
return -EINVAL;
ctrl_val |= (NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN);
if (tx_mask & 0xf0) {
tslot_l = 4 * slot_width;
ctrl_val |= (tx_mask >> 4);
} else {
ctrl_val |= tx_mask;
}
if (rx_mask & 0xf0)
ctrl_val |= ((rx_mask >> 4) << NAU8824_TDM_DACR_RX_SFT);
else
ctrl_val |= (rx_mask << NAU8824_TDM_DACR_RX_SFT);
regmap_update_bits(nau8824->regmap, NAU8824_REG_TDM_CTRL,
NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN |
NAU8824_TDM_DACL_RX_MASK | NAU8824_TDM_DACR_RX_MASK |
NAU8824_TDM_TX_MASK, ctrl_val);
regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_LEFT_TIME_SLOT,
NAU8824_TSLOT_L_MASK, tslot_l);
return 0;
}
/** /**
* nau8824_calc_fll_param - Calculate FLL parameters. * nau8824_calc_fll_param - Calculate FLL parameters.
* @fll_in: external clock provided to codec. * @fll_in: external clock provided to codec.
...@@ -1440,6 +1491,7 @@ static struct snd_soc_codec_driver nau8824_codec_driver = { ...@@ -1440,6 +1491,7 @@ static struct snd_soc_codec_driver nau8824_codec_driver = {
static const struct snd_soc_dai_ops nau8824_dai_ops = { static const struct snd_soc_dai_ops nau8824_dai_ops = {
.hw_params = nau8824_hw_params, .hw_params = nau8824_hw_params,
.set_fmt = nau8824_set_fmt, .set_fmt = nau8824_set_fmt,
.set_tdm_slot = nau8824_set_tdm_slot,
}; };
#define NAU8824_RATES SNDRV_PCM_RATE_8000_192000 #define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
......
...@@ -258,6 +258,18 @@ ...@@ -258,6 +258,18 @@
#define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT) #define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT)
#define NAU8824_I2S_BLK_DIV_MASK 0x7 #define NAU8824_I2S_BLK_DIV_MASK 0x7
/* PORT0_LEFT_TIME_SLOT (0x1E) */
#define NAU8824_TSLOT_L_MASK 0x3ff
/* TDM_CTRL (0x20) */
#define NAU8824_TDM_MODE (0x1 << 15)
#define NAU8824_TDM_OFFSET_EN (0x1 << 14)
#define NAU8824_TDM_DACL_RX_SFT 6
#define NAU8824_TDM_DACL_RX_MASK (0x3 << NAU8824_TDM_DACL_RX_SFT)
#define NAU8824_TDM_DACR_RX_SFT 4
#define NAU8824_TDM_DACR_RX_MASK (0x3 << NAU8824_TDM_DACR_RX_SFT)
#define NAU8824_TDM_TX_MASK 0xf
/* ADC_FILTER_CTRL (0x24) */ /* ADC_FILTER_CTRL (0x24) */
#define NAU8824_ADC_SYNC_DOWN_MASK 0x3 #define NAU8824_ADC_SYNC_DOWN_MASK 0x3
#define NAU8824_ADC_SYNC_DOWN_32 0 #define NAU8824_ADC_SYNC_DOWN_32 0
......
...@@ -1612,7 +1612,6 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) ...@@ -1612,7 +1612,6 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
snd_soc_dapm_sync(dapm); snd_soc_dapm_sync(dapm);
break; break;
case 2: case 2:
case 3:
dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n"); dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
type = SND_JACK_HEADSET; type = SND_JACK_HEADSET;
...@@ -1632,6 +1631,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) ...@@ -1632,6 +1631,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
snd_soc_dapm_force_enable_pin(dapm, "SAR"); snd_soc_dapm_force_enable_pin(dapm, "SAR");
snd_soc_dapm_sync(dapm); snd_soc_dapm_sync(dapm);
break; break;
case 3:
/* detect error case */
dev_err(nau8825->dev, "detection error; disable mic function\n");
type = SND_JACK_HEADPHONE;
break;
} }
/* Leaving HPOL/R grounded after jack insert by default. They will be /* Leaving HPOL/R grounded after jack insert by default. They will be
...@@ -1682,7 +1686,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) ...@@ -1682,7 +1686,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
if (nau8825_is_jack_inserted(regmap)) { if (nau8825_is_jack_inserted(regmap)) {
event |= nau8825_jack_insert(nau8825); event |= nau8825_jack_insert(nau8825);
if (!nau8825->high_imped) { if (!nau8825->xtalk_bypass && !nau8825->high_imped) {
/* Apply the cross talk suppression in the /* Apply the cross talk suppression in the
* headset without high impedance. * headset without high impedance.
*/ */
...@@ -2328,6 +2332,13 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, ...@@ -2328,6 +2332,13 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* Reset the configuration of jack type for detection */
/* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
regmap_update_bits(nau8825->regmap, NAU8825_REG_MIC_BIAS,
NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
/* ground HPL/HPR, MICGRND1/2 */
regmap_update_bits(nau8825->regmap,
NAU8825_REG_HSD_CTRL, 0xf, 0xf);
/* Cancel and reset cross talk detection funciton */ /* Cancel and reset cross talk detection funciton */
nau8825_xtalk_cancel(nau8825); nau8825_xtalk_cancel(nau8825);
/* Turn off all interruptions before system shutdown. Keep the /* Turn off all interruptions before system shutdown. Keep the
...@@ -2351,6 +2362,10 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec) ...@@ -2351,6 +2362,10 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
disable_irq(nau8825->irq); disable_irq(nau8825->irq);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
/* Power down codec power; don't suppoet button wakeup */
snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
snd_soc_dapm_sync(nau8825->dapm);
regcache_cache_only(nau8825->regmap, true); regcache_cache_only(nau8825->regmap, true);
regcache_mark_dirty(nau8825->regmap); regcache_mark_dirty(nau8825->regmap);
...@@ -2425,10 +2440,13 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) ...@@ -2425,10 +2440,13 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
nau8825->jack_insert_debounce); nau8825->jack_insert_debounce);
dev_dbg(dev, "jack-eject-debounce: %d\n", dev_dbg(dev, "jack-eject-debounce: %d\n",
nau8825->jack_eject_debounce); nau8825->jack_eject_debounce);
dev_dbg(dev, "crosstalk-bypass: %d\n",
nau8825->xtalk_bypass);
} }
static int nau8825_read_device_properties(struct device *dev, static int nau8825_read_device_properties(struct device *dev,
struct nau8825 *nau8825) { struct nau8825 *nau8825) {
int ret;
nau8825->jkdet_enable = device_property_read_bool(dev, nau8825->jkdet_enable = device_property_read_bool(dev,
"nuvoton,jkdet-enable"); "nuvoton,jkdet-enable");
...@@ -2436,30 +2454,60 @@ static int nau8825_read_device_properties(struct device *dev, ...@@ -2436,30 +2454,60 @@ static int nau8825_read_device_properties(struct device *dev,
"nuvoton,jkdet-pull-enable"); "nuvoton,jkdet-pull-enable");
nau8825->jkdet_pull_up = device_property_read_bool(dev, nau8825->jkdet_pull_up = device_property_read_bool(dev,
"nuvoton,jkdet-pull-up"); "nuvoton,jkdet-pull-up");
device_property_read_u32(dev, "nuvoton,jkdet-polarity", ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
&nau8825->jkdet_polarity); &nau8825->jkdet_polarity);
device_property_read_u32(dev, "nuvoton,micbias-voltage", if (ret)
nau8825->jkdet_polarity = 1;
ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
&nau8825->micbias_voltage); &nau8825->micbias_voltage);
device_property_read_u32(dev, "nuvoton,vref-impedance", if (ret)
nau8825->micbias_voltage = 6;
ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
&nau8825->vref_impedance); &nau8825->vref_impedance);
device_property_read_u32(dev, "nuvoton,sar-threshold-num", if (ret)
nau8825->vref_impedance = 2;
ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
&nau8825->sar_threshold_num); &nau8825->sar_threshold_num);
device_property_read_u32_array(dev, "nuvoton,sar-threshold", if (ret)
nau8825->sar_threshold_num = 4;
ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
nau8825->sar_threshold, nau8825->sar_threshold_num); nau8825->sar_threshold, nau8825->sar_threshold_num);
device_property_read_u32(dev, "nuvoton,sar-hysteresis", if (ret) {
nau8825->sar_threshold[0] = 0x08;
nau8825->sar_threshold[1] = 0x12;
nau8825->sar_threshold[2] = 0x26;
nau8825->sar_threshold[3] = 0x73;
}
ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
&nau8825->sar_hysteresis); &nau8825->sar_hysteresis);
device_property_read_u32(dev, "nuvoton,sar-voltage", if (ret)
nau8825->sar_hysteresis = 0;
ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
&nau8825->sar_voltage); &nau8825->sar_voltage);
device_property_read_u32(dev, "nuvoton,sar-compare-time", if (ret)
nau8825->sar_voltage = 6;
ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
&nau8825->sar_compare_time); &nau8825->sar_compare_time);
device_property_read_u32(dev, "nuvoton,sar-sampling-time", if (ret)
nau8825->sar_compare_time = 1;
ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
&nau8825->sar_sampling_time); &nau8825->sar_sampling_time);
device_property_read_u32(dev, "nuvoton,short-key-debounce", if (ret)
nau8825->sar_sampling_time = 1;
ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
&nau8825->key_debounce); &nau8825->key_debounce);
device_property_read_u32(dev, "nuvoton,jack-insert-debounce", if (ret)
nau8825->key_debounce = 3;
ret = device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
&nau8825->jack_insert_debounce); &nau8825->jack_insert_debounce);
device_property_read_u32(dev, "nuvoton,jack-eject-debounce", if (ret)
nau8825->jack_insert_debounce = 7;
ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
&nau8825->jack_eject_debounce); &nau8825->jack_eject_debounce);
if (ret)
nau8825->jack_eject_debounce = 0;
nau8825->xtalk_bypass = device_property_read_bool(dev,
"nuvoton,crosstalk-bypass");
nau8825->mclk = devm_clk_get(dev, "mclk"); nau8825->mclk = devm_clk_get(dev, "mclk");
if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
......
...@@ -476,6 +476,7 @@ struct nau8825 { ...@@ -476,6 +476,7 @@ struct nau8825 {
int xtalk_event_mask; int xtalk_event_mask;
bool xtalk_protect; bool xtalk_protect;
int imp_rms[NAU8825_XTALK_IMM]; int imp_rms[NAU8825_XTALK_IMM];
int xtalk_bypass;
}; };
int nau8825_enable_jack_detect(struct snd_soc_codec *codec, int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/acpi.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -395,14 +396,14 @@ static const char * const rt5514_dmic_src[] = { ...@@ -395,14 +396,14 @@ static const char * const rt5514_dmic_src[] = {
"DMIC1", "DMIC2" "DMIC1", "DMIC2"
}; };
static const SOC_ENUM_SINGLE_DECL( static SOC_ENUM_SINGLE_DECL(
rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL, rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL,
RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
static const struct snd_kcontrol_new rt5514_sto1_dmic_mux = static const struct snd_kcontrol_new rt5514_sto1_dmic_mux =
SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum); SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum);
static const SOC_ENUM_SINGLE_DECL( static SOC_ENUM_SINGLE_DECL(
rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL, rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL,
RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
...@@ -906,9 +907,23 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ...@@ -906,9 +907,23 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
if (rx_mask || tx_mask) if (rx_mask || tx_mask)
val |= RT5514_TDM_MODE; val |= RT5514_TDM_MODE;
if (slots == 4) switch (slots) {
case 4:
val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH; val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH;
break;
case 6:
val |= RT5514_TDMSLOT_SEL_RX_6CH | RT5514_TDMSLOT_SEL_TX_6CH;
break;
case 8:
val |= RT5514_TDMSLOT_SEL_RX_8CH | RT5514_TDMSLOT_SEL_TX_8CH;
break;
case 2:
default:
break;
}
switch (slot_width) { switch (slot_width) {
case 20: case 20:
...@@ -919,6 +934,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ...@@ -919,6 +934,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24; val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24;
break; break;
case 25:
val |= RT5514_TDM_MODE2;
break;
case 32: case 32:
val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32; val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32;
break; break;
...@@ -930,7 +949,8 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ...@@ -930,7 +949,8 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE | regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE |
RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK | RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK |
RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK, val); RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK |
RT5514_TDM_MODE2, val);
return 0; return 0;
} }
...@@ -1076,6 +1096,14 @@ static const struct of_device_id rt5514_of_match[] = { ...@@ -1076,6 +1096,14 @@ static const struct of_device_id rt5514_of_match[] = {
MODULE_DEVICE_TABLE(of, rt5514_of_match); MODULE_DEVICE_TABLE(of, rt5514_of_match);
#endif #endif
#ifdef CONFIG_ACPI
static struct acpi_device_id rt5514_acpi_match[] = {
{ "10EC5514", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match);
#endif
static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev) static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev)
{ {
device_property_read_u32(dev, "realtek,dmic-init-delay-ms", device_property_read_u32(dev, "realtek,dmic-init-delay-ms",
...@@ -1179,6 +1207,7 @@ static const struct dev_pm_ops rt5514_i2_pm_ops = { ...@@ -1179,6 +1207,7 @@ static const struct dev_pm_ops rt5514_i2_pm_ops = {
static struct i2c_driver rt5514_i2c_driver = { static struct i2c_driver rt5514_i2c_driver = {
.driver = { .driver = {
.name = "rt5514", .name = "rt5514",
.acpi_match_table = ACPI_PTR(rt5514_acpi_match),
.of_match_table = of_match_ptr(rt5514_of_match), .of_match_table = of_match_ptr(rt5514_of_match),
.pm = &rt5514_i2_pm_ops, .pm = &rt5514_i2_pm_ops,
}, },
......
...@@ -117,6 +117,8 @@ ...@@ -117,6 +117,8 @@
#define RT5514_POW_ADCFEDL_BIT 0 #define RT5514_POW_ADCFEDL_BIT 0
/* RT5514_I2S_CTRL1 (0x2010) */ /* RT5514_I2S_CTRL1 (0x2010) */
#define RT5514_TDM_MODE2 (0x1 << 30)
#define RT5514_TDM_MODE2_SFT 30
#define RT5514_TDM_MODE (0x1 << 28) #define RT5514_TDM_MODE (0x1 << 28)
#define RT5514_TDM_MODE_SFT 28 #define RT5514_TDM_MODE_SFT 28
#define RT5514_I2S_LR_MASK (0x1 << 26) #define RT5514_I2S_LR_MASK (0x1 << 26)
...@@ -136,6 +138,8 @@ ...@@ -136,6 +138,8 @@
#define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10) #define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10)
#define RT5514_TDMSLOT_SEL_RX_SFT 10 #define RT5514_TDMSLOT_SEL_RX_SFT 10
#define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10) #define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10)
#define RT5514_TDMSLOT_SEL_RX_6CH (0x2 << 10)
#define RT5514_TDMSLOT_SEL_RX_8CH (0x3 << 10)
#define RT5514_CH_LEN_RX_MASK (0x3 << 8) #define RT5514_CH_LEN_RX_MASK (0x3 << 8)
#define RT5514_CH_LEN_RX_SFT 8 #define RT5514_CH_LEN_RX_SFT 8
#define RT5514_CH_LEN_RX_16 (0x0 << 8) #define RT5514_CH_LEN_RX_16 (0x0 << 8)
...@@ -145,6 +149,8 @@ ...@@ -145,6 +149,8 @@
#define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6) #define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6)
#define RT5514_TDMSLOT_SEL_TX_SFT 6 #define RT5514_TDMSLOT_SEL_TX_SFT 6
#define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6) #define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6)
#define RT5514_TDMSLOT_SEL_TX_6CH (0x2 << 6)
#define RT5514_TDMSLOT_SEL_TX_8CH (0x3 << 6)
#define RT5514_CH_LEN_TX_MASK (0x3 << 4) #define RT5514_CH_LEN_TX_MASK (0x3 << 4)
#define RT5514_CH_LEN_TX_SFT 4 #define RT5514_CH_LEN_TX_SFT 4
#define RT5514_CH_LEN_TX_16 (0x0 << 4) #define RT5514_CH_LEN_TX_16 (0x0 << 4)
......
...@@ -34,6 +34,17 @@ ...@@ -34,6 +34,17 @@
#include "rl6231.h" #include "rl6231.h"
#include "rt5645.h" #include "rt5645.h"
#define QUIRK_INV_JD1_1(q) ((q) & 1)
#define QUIRK_LEVEL_IRQ(q) (((q) >> 1) & 1)
#define QUIRK_IN2_DIFF(q) (((q) >> 2) & 1)
#define QUIRK_JD_MODE(q) (((q) >> 4) & 7)
#define QUIRK_DMIC1_DATA_PIN(q) (((q) >> 8) & 3)
#define QUIRK_DMIC2_DATA_PIN(q) (((q) >> 12) & 3)
static unsigned int quirk = -1;
module_param(quirk, uint, 0444);
MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
#define RT5645_DEVICE_ID 0x6308 #define RT5645_DEVICE_ID 0x6308
#define RT5650_DEVICE_ID 0x6419 #define RT5650_DEVICE_ID 0x6419
...@@ -59,7 +70,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = { ...@@ -59,7 +70,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = {
static const struct reg_sequence init_list[] = { static const struct reg_sequence init_list[] = {
{RT5645_PR_BASE + 0x3d, 0x3600}, {RT5645_PR_BASE + 0x3d, 0x3600},
{RT5645_PR_BASE + 0x1c, 0xfd20}, {RT5645_PR_BASE + 0x1c, 0xfd70},
{RT5645_PR_BASE + 0x20, 0x611f}, {RT5645_PR_BASE + 0x20, 0x611f},
{RT5645_PR_BASE + 0x21, 0x4040}, {RT5645_PR_BASE + 0x21, 0x4040},
{RT5645_PR_BASE + 0x23, 0x0004}, {RT5645_PR_BASE + 0x23, 0x0004},
...@@ -3151,7 +3162,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) ...@@ -3151,7 +3162,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
snd_soc_dapm_sync(dapm); snd_soc_dapm_sync(dapm);
rt5645->jack_type = SND_JACK_HEADPHONE; rt5645->jack_type = SND_JACK_HEADPHONE;
} }
if (rt5645->pdata.jd_invert) if (rt5645->pdata.level_trigger_irq)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
} else { /* jack out */ } else { /* jack out */
...@@ -3172,7 +3183,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) ...@@ -3172,7 +3183,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
snd_soc_dapm_disable_pin(dapm, "LDO2"); snd_soc_dapm_disable_pin(dapm, "LDO2");
snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm); snd_soc_dapm_sync(dapm);
if (rt5645->pdata.jd_invert) if (rt5645->pdata.level_trigger_irq)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
} }
...@@ -3238,24 +3249,16 @@ static void rt5645_jack_detect_work(struct work_struct *work) ...@@ -3238,24 +3249,16 @@ static void rt5645_jack_detect_work(struct work_struct *work)
snd_soc_jack_report(rt5645->mic_jack, snd_soc_jack_report(rt5645->mic_jack,
report, SND_JACK_MICROPHONE); report, SND_JACK_MICROPHONE);
return; return;
case 1: /* 2 port */ default: /* read rt5645 jd1_1 status */
val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070; val = snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x1000;
break;
default: /* 1 port */
val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020;
break; break;
} }
switch (val) { if (!val && (rt5645->jack_type == 0)) { /* jack in */
/* jack in */ report = rt5645_jack_detect(rt5645->codec, 1);
case 0x30: /* 2 port */ } else if (!val && rt5645->jack_type != 0) {
case 0x0: /* 1 port or 2 port */ /* for push button and jack out */
if (rt5645->jack_type == 0) {
report = rt5645_jack_detect(rt5645->codec, 1);
/* for push button and jack out */
break;
}
btn_type = 0; btn_type = 0;
if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) { if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
/* button pressed */ /* button pressed */
...@@ -3302,19 +3305,12 @@ static void rt5645_jack_detect_work(struct work_struct *work) ...@@ -3302,19 +3305,12 @@ static void rt5645_jack_detect_work(struct work_struct *work)
mod_timer(&rt5645->btn_check_timer, mod_timer(&rt5645->btn_check_timer,
msecs_to_jiffies(100)); msecs_to_jiffies(100));
} }
} else {
break; /* jack out */
/* jack out */
case 0x70: /* 2 port */
case 0x10: /* 2 port */
case 0x20: /* 1 port */
report = 0; report = 0;
snd_soc_update_bits(rt5645->codec, snd_soc_update_bits(rt5645->codec,
RT5645_INT_IRQ_ST, 0x1, 0x0); RT5645_INT_IRQ_ST, 0x1, 0x0);
rt5645_jack_detect(rt5645->codec, 0); rt5645_jack_detect(rt5645->codec, 0);
break;
default:
break;
} }
snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
...@@ -3601,7 +3597,7 @@ static struct rt5645_platform_data buddy_platform_data = { ...@@ -3601,7 +3597,7 @@ static struct rt5645_platform_data buddy_platform_data = {
.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
.dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
.jd_mode = 3, .jd_mode = 3,
.jd_invert = true, .level_trigger_irq = true,
}; };
static struct dmi_system_id dmi_platform_intel_broadwell[] = { static struct dmi_system_id dmi_platform_intel_broadwell[] = {
...@@ -3614,6 +3610,33 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = { ...@@ -3614,6 +3610,33 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = {
{ } { }
}; };
static struct rt5645_platform_data gpd_win_platform_data = {
.jd_mode = 3,
.inv_jd1_1 = true,
};
static const struct dmi_system_id dmi_platform_gpd_win[] = {
{
/*
* Match for the GPDwin which unfortunately uses somewhat
* generic dmi strings, which is why we test for 4 strings.
* Comparing against 23 other byt/cht boards, board_vendor
* and board_name are unique to the GPDwin, where as only one
* other board has the same board_serial and 3 others have
* the same default product_name. Also the GPDwin is the
* only device to have both board_ and product_name not set.
*/
.ident = "GPD Win",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Default string"),
DMI_MATCH(DMI_BOARD_SERIAL, "Default string"),
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
},
},
{}
};
static bool rt5645_check_dp(struct device *dev) static bool rt5645_check_dp(struct device *dev)
{ {
if (device_property_present(dev, "realtek,in2-differential") || if (device_property_present(dev, "realtek,in2-differential") ||
...@@ -3664,6 +3687,17 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ...@@ -3664,6 +3687,17 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
rt5645_parse_dt(rt5645, &i2c->dev); rt5645_parse_dt(rt5645, &i2c->dev);
else if (dmi_check_system(dmi_platform_intel_braswell)) else if (dmi_check_system(dmi_platform_intel_braswell))
rt5645->pdata = general_platform_data; rt5645->pdata = general_platform_data;
else if (dmi_check_system(dmi_platform_gpd_win))
rt5645->pdata = gpd_win_platform_data;
if (quirk != -1) {
rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk);
rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
}
rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
GPIOD_IN); GPIOD_IN);
...@@ -3745,6 +3779,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ...@@ -3745,6 +3779,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
ret); ret);
} }
regmap_update_bits(rt5645->regmap, RT5645_CLSD_OUT_CTRL, 0xc0, 0xc0);
if (rt5645->pdata.in2_diff) if (rt5645->pdata.in2_diff)
regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
RT5645_IN_DF2, RT5645_IN_DF2); RT5645_IN_DF2, RT5645_IN_DF2);
...@@ -3848,12 +3884,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ...@@ -3848,12 +3884,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
default: default:
break; break;
} }
if (rt5645->pdata.inv_jd1_1) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
}
} }
regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1, regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2); RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
if (rt5645->pdata.jd_invert) { if (rt5645->pdata.level_trigger_irq) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
} }
......
...@@ -586,44 +586,6 @@ static const struct snd_kcontrol_new hpo_r_mute_control = ...@@ -586,44 +586,6 @@ static const struct snd_kcontrol_new hpo_r_mute_control =
SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL, SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
RT5651_R_MUTE_SFT, 1, 1); RT5651_R_MUTE_SFT, 1, 1);
/* INL/R source */
static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"};
static SOC_ENUM_SINGLE_DECL(
rt5651_inl_enum, RT5651_INL1_INR1_VOL,
RT5651_INL_SEL_SFT, rt5651_inl_src);
static const struct snd_kcontrol_new rt5651_inl1_mux =
SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum);
static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"};
static SOC_ENUM_SINGLE_DECL(
rt5651_inr1_enum, RT5651_INL1_INR1_VOL,
RT5651_INR_SEL_SFT, rt5651_inr1_src);
static const struct snd_kcontrol_new rt5651_inr1_mux =
SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum);
static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"};
static SOC_ENUM_SINGLE_DECL(
rt5651_inl2_enum, RT5651_INL2_INR2_VOL,
RT5651_INL_SEL_SFT, rt5651_inl2_src);
static const struct snd_kcontrol_new rt5651_inl2_mux =
SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum);
static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"};
static SOC_ENUM_SINGLE_DECL(
rt5651_inr2_enum, RT5651_INL2_INR2_VOL,
RT5651_INR_SEL_SFT, rt5651_inr2_src);
static const struct snd_kcontrol_new rt5651_inr2_mux =
SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum);
/* Stereo ADC source */ /* Stereo ADC source */
static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"}; static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"};
...@@ -955,11 +917,7 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { ...@@ -955,11 +917,7 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
RT5651_PWR_IN2_L_BIT, 0, NULL, 0), RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL, SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL,
RT5651_PWR_IN2_R_BIT, 0, NULL, 0), RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
/* IN Mux */
SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux),
SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux),
SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux),
SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux),
/* REC Mixer */ /* REC Mixer */
SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0, SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0,
rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)), rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)),
......
This diff is collapsed.
...@@ -2022,7 +2022,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { ...@@ -2022,7 +2022,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
{ "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" }, { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
{ "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
{ "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" }, { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
...@@ -2061,7 +2060,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { ...@@ -2061,7 +2060,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
{ "Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter" }, { "Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter" },
{ "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll },
{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
{ "Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter" }, { "Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter" },
...@@ -2444,10 +2442,9 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -2444,10 +2442,9 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0; return 0;
} }
static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, static int rt5670_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
int clk_id, unsigned int freq, int dir) int source, unsigned int freq, int dir)
{ {
struct snd_soc_codec *codec = dai->codec;
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
unsigned int reg_val = 0; unsigned int reg_val = 0;
...@@ -2471,7 +2468,7 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, ...@@ -2471,7 +2468,7 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
if (clk_id != RT5670_SCLK_S_RCCLK) if (clk_id != RT5670_SCLK_S_RCCLK)
rt5670->sysclk_src = clk_id; rt5670->sysclk_src = clk_id;
dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); dev_dbg(codec->dev, "Sysclk : %dHz clock id : %d\n", freq, clk_id);
return 0; return 0;
} }
...@@ -2723,7 +2720,6 @@ static int rt5670_resume(struct snd_soc_codec *codec) ...@@ -2723,7 +2720,6 @@ static int rt5670_resume(struct snd_soc_codec *codec)
static const struct snd_soc_dai_ops rt5670_aif_dai_ops = { static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
.hw_params = rt5670_hw_params, .hw_params = rt5670_hw_params,
.set_fmt = rt5670_set_dai_fmt, .set_fmt = rt5670_set_dai_fmt,
.set_sysclk = rt5670_set_dai_sysclk,
.set_tdm_slot = rt5670_set_tdm_slot, .set_tdm_slot = rt5670_set_tdm_slot,
.set_pll = rt5670_set_dai_pll, .set_pll = rt5670_set_dai_pll,
}; };
...@@ -2776,6 +2772,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { ...@@ -2776,6 +2772,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
.resume = rt5670_resume, .resume = rt5670_resume,
.set_bias_level = rt5670_set_bias_level, .set_bias_level = rt5670_set_bias_level,
.idle_bias_off = true, .idle_bias_off = true,
.set_sysclk = rt5670_set_codec_sysclk,
.component_driver = { .component_driver = {
.controls = rt5670_snd_controls, .controls = rt5670_snd_controls,
.num_controls = ARRAY_SIZE(rt5670_snd_controls), .num_controls = ARRAY_SIZE(rt5670_snd_controls),
......
...@@ -74,6 +74,20 @@ static const struct reg_default sgtl5000_reg_defaults[] = { ...@@ -74,6 +74,20 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
{ SGTL5000_DAP_AVC_DECAY, 0x0050 }, { SGTL5000_DAP_AVC_DECAY, 0x0050 },
}; };
/* AVC: Threshold dB -> register: pre-calculated values */
static const u16 avc_thr_db2reg[97] = {
0x5168, 0x488E, 0x40AA, 0x39A1, 0x335D, 0x2DC7, 0x28CC, 0x245D, 0x2068,
0x1CE2, 0x19BE, 0x16F1, 0x1472, 0x1239, 0x103E, 0x0E7A, 0x0CE6, 0x0B7F,
0x0A3F, 0x0922, 0x0824, 0x0741, 0x0677, 0x05C3, 0x0522, 0x0493, 0x0414,
0x03A2, 0x033D, 0x02E3, 0x0293, 0x024B, 0x020B, 0x01D2, 0x019F, 0x0172,
0x014A, 0x0126, 0x0106, 0x00E9, 0x00D0, 0x00B9, 0x00A5, 0x0093, 0x0083,
0x0075, 0x0068, 0x005D, 0x0052, 0x0049, 0x0041, 0x003A, 0x0034, 0x002E,
0x0029, 0x0025, 0x0021, 0x001D, 0x001A, 0x0017, 0x0014, 0x0012, 0x0010,
0x000E, 0x000D, 0x000B, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006, 0x0005,
0x0005, 0x0004, 0x0004, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
/* regulator supplies for sgtl5000, VDDD is an optional external supply */ /* regulator supplies for sgtl5000, VDDD is an optional external supply */
enum sgtl5000_regulator_supplies { enum sgtl5000_regulator_supplies {
VDDA, VDDA,
...@@ -382,6 +396,65 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -382,6 +396,65 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
/*
* custom function to get AVC threshold
*
* The threshold dB is calculated by rearranging the calculation from the
* avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
* dB = ( fls(register_value) - 14.347 ) * 6.02
*
* As this calculation is expensive and the threshold dB values may not exeed
* 0 to 96 we use pre-calculated values.
*/
static int avc_get_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int db, i;
u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
/* register value 0 => -96dB */
if (!reg) {
ucontrol->value.integer.value[0] = 96;
ucontrol->value.integer.value[1] = 96;
return 0;
}
/* get dB from register value (rounded down) */
for (i = 0; avc_thr_db2reg[i] > reg; i++)
;
db = i;
ucontrol->value.integer.value[0] = db;
ucontrol->value.integer.value[1] = db;
return 0;
}
/*
* custom function to put AVC threshold
*
* The register value is calculated by following formula:
* register_value = 10^(dB/20) * 0.636 * 2^15
* As this calculation is expensive and the threshold dB values may not exeed
* 0 to 96 we use pre-calculated values.
*/
static int avc_put_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int db;
u16 reg;
db = (int)ucontrol->value.integer.value[0];
if (db < 0 || db > 96)
return -EINVAL;
reg = avc_thr_db2reg[db];
snd_soc_write(codec, SGTL5000_DAP_AVC_THRESHOLD, reg);
return 0;
}
static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
/* tlv for mic gain, 0db 20db 30db 40db */ /* tlv for mic gain, 0db 20db 30db 40db */
...@@ -396,6 +469,12 @@ static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); ...@@ -396,6 +469,12 @@ static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
/* tlv for lineout volume, 31 steps of .5db each */ /* tlv for lineout volume, 31 steps of .5db each */
static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0); static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0);
/* tlv for dap avc max gain, 0db, 6db, 12db */
static const DECLARE_TLV_DB_SCALE(avc_max_gain, 0, 600, 0);
/* tlv for dap avc threshold, */
static const DECLARE_TLV_DB_MINMAX(avc_threshold, 0, 9600);
static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
/* SOC_DOUBLE_S8_TLV with invert */ /* SOC_DOUBLE_S8_TLV with invert */
{ {
...@@ -434,6 +513,16 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { ...@@ -434,6 +513,16 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
0x1f, 1, 0x1f, 1,
lineout_volume), lineout_volume),
SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1), SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
/* Automatic Volume Control (DAP AVC) */
SOC_SINGLE("AVC Switch", SGTL5000_DAP_AVC_CTRL, 0, 1, 0),
SOC_SINGLE("AVC Hard Limiter Switch", SGTL5000_DAP_AVC_CTRL, 5, 1, 0),
SOC_SINGLE_TLV("AVC Max Gain Volume", SGTL5000_DAP_AVC_CTRL, 12, 2, 0,
avc_max_gain),
SOC_SINGLE("AVC Integrator Response", SGTL5000_DAP_AVC_CTRL, 8, 3, 0),
SOC_SINGLE_EXT_TLV("AVC Threshold Volume", SGTL5000_DAP_AVC_THRESHOLD,
0, 96, 0, avc_get_threshold, avc_put_threshold,
avc_threshold),
}; };
/* mute the codec used by alsa core */ /* mute the codec used by alsa core */
......
...@@ -1210,7 +1210,7 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = { ...@@ -1210,7 +1210,7 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = {
static struct snd_soc_dai_driver dac31xx_dai_driver[] = { static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
{ {
.name = "tlv32dac31xx-hifi", .name = "tlv320dac31xx-hifi",
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 2, .channels_min = 2,
......
...@@ -482,8 +482,6 @@ struct wm_coeff_ctl_ops { ...@@ -482,8 +482,6 @@ struct wm_coeff_ctl_ops {
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int (*xput)(struct snd_kcontrol *kcontrol, int (*xput)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int (*xinfo)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
}; };
struct wm_coeff_ctl { struct wm_coeff_ctl {
...@@ -1890,7 +1888,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, ...@@ -1890,7 +1888,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
} }
if (be32_to_cpu(val) != 0xbedead) if (be32_to_cpu(val) != 0xbedead)
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
pos + len, be32_to_cpu(val)); pos + len, be32_to_cpu(val));
alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
...@@ -2654,7 +2652,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, ...@@ -2654,7 +2652,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
char preload[32]; char preload[32];
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift); snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift);
dsp->preloaded = ucontrol->value.integer.value[0]; dsp->preloaded = ucontrol->value.integer.value[0];
......
This diff is collapsed.
...@@ -302,7 +302,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) ...@@ -302,7 +302,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_card *card = rtd->card->snd_card; struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm; struct snd_pcm *pcm = rtd->pcm;
struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
size_t size = psc_dma_hardware.buffer_bytes_max; size_t size = psc_dma_hardware.buffer_bytes_max;
int rc; int rc;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -30,6 +31,34 @@ struct graph_card_data { ...@@ -30,6 +31,34 @@ struct graph_card_data {
struct asoc_simple_dai codec_dai; struct asoc_simple_dai codec_dai;
} *dai_props; } *dai_props;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
struct gpio_desc *pa_gpio;
};
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
gpiod_set_value_cansleep(priv->pa_gpio, 1);
break;
case SND_SOC_DAPM_PRE_PMD:
gpiod_set_value_cansleep(priv->pa_gpio, 0);
break;
default:
return -EINVAL;
}
return 0;
}
static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
0, 0, NULL, 0, asoc_graph_card_outdrv_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
}; };
#define graph_priv_to_card(priv) (&(priv)->snd_card) #define graph_priv_to_card(priv) (&(priv)->snd_card)
...@@ -44,13 +73,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) ...@@ -44,13 +73,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret; int ret;
ret = clk_prepare_enable(dai_props->cpu_dai.clk); ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(dai_props->codec_dai.clk); ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
if (ret) if (ret)
clk_disable_unprepare(dai_props->cpu_dai.clk); asoc_simple_card_clk_disable(&dai_props->cpu_dai);
return ret; return ret;
} }
...@@ -61,9 +90,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) ...@@ -61,9 +90,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
clk_disable_unprepare(dai_props->cpu_dai.clk); asoc_simple_card_clk_disable(&dai_props->cpu_dai);
clk_disable_unprepare(dai_props->codec_dai.clk); asoc_simple_card_clk_disable(&dai_props->codec_dai);
} }
static struct snd_soc_ops asoc_graph_card_ops = { static struct snd_soc_ops asoc_graph_card_ops = {
...@@ -100,7 +129,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, ...@@ -100,7 +129,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
struct snd_soc_card *card = graph_priv_to_card(priv);
struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL); struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep); struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep); struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
...@@ -131,19 +159,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, ...@@ -131,19 +159,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = snd_soc_of_parse_tdm_slot(cpu_ep, ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
&cpu_dai->tx_slot_mask,
&cpu_dai->rx_slot_mask,
&cpu_dai->slots,
&cpu_dai->slot_width);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = snd_soc_of_parse_tdm_slot(codec_ep, ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
&codec_dai->tx_slot_mask,
&codec_dai->rx_slot_mask,
&codec_dai->slots,
&codec_dai->slot_width);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
...@@ -170,7 +190,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, ...@@ -170,7 +190,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
dai_link->init = asoc_graph_card_dai_init; dai_link->init = asoc_graph_card_dai_init;
asoc_simple_card_canonicalize_cpu(dai_link, asoc_simple_card_canonicalize_cpu(dai_link,
card->num_links == 1); of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
dai_link_of_err: dai_link_of_err:
of_node_put(cpu_ep); of_node_put(cpu_ep);
...@@ -189,8 +209,16 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -189,8 +209,16 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
int rc, idx = 0; int rc, idx = 0;
int ret; int ret;
ret = asoc_simple_card_of_parse_widgets(card, NULL);
if (ret < 0)
return ret;
ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
if (ret < 0)
return ret;
/* /*
* we need to consider "widgets", "routing", "mclk-fs" around here * we need to consider "mclk-fs" around here
* see simple-card * see simple-card
*/ */
...@@ -242,6 +270,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev) ...@@ -242,6 +270,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
if (!dai_props || !dai_link) if (!dai_props || !dai_link)
return -ENOMEM; return -ENOMEM;
priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
if (IS_ERR(priv->pa_gpio)) {
ret = PTR_ERR(priv->pa_gpio);
dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
return ret;
}
priv->dai_props = dai_props; priv->dai_props = dai_props;
priv->dai_link = dai_link; priv->dai_link = dai_link;
...@@ -251,6 +286,8 @@ static int asoc_graph_card_probe(struct platform_device *pdev) ...@@ -251,6 +286,8 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
card->dev = dev; card->dev = dev;
card->dai_link = dai_link; card->dai_link = dai_link;
card->num_links = num; card->num_links = num;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
ret = asoc_graph_card_parse_of(priv); ret = asoc_graph_card_parse_of(priv);
if (ret < 0) { if (ret < 0) {
......
...@@ -30,8 +30,7 @@ struct graph_card_data { ...@@ -30,8 +30,7 @@ struct graph_card_data {
struct snd_soc_codec_conf codec_conf; struct snd_soc_codec_conf codec_conf;
struct asoc_simple_dai *dai_props; struct asoc_simple_dai *dai_props;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
u32 convert_rate; struct asoc_simple_card_data adata;
u32 convert_channels;
}; };
#define graph_priv_to_card(priv) (&(priv)->snd_card) #define graph_priv_to_card(priv) (&(priv)->snd_card)
...@@ -45,7 +44,7 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) ...@@ -45,7 +44,7 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
return clk_prepare_enable(dai_props->clk); return asoc_simple_card_clk_enable(dai_props);
} }
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
...@@ -54,7 +53,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) ...@@ -54,7 +53,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
clk_disable_unprepare(dai_props->clk); asoc_simple_card_clk_disable(dai_props);
} }
static struct snd_soc_ops asoc_graph_card_ops = { static struct snd_soc_ops asoc_graph_card_ops = {
...@@ -83,18 +82,8 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -83,18 +82,8 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (priv->convert_rate) asoc_simple_card_convert_fixup(&priv->adata, params);
rate->min =
rate->max = priv->convert_rate;
if (priv->convert_channels)
channels->min =
channels->max = priv->convert_channels;
return 0; return 0;
} }
...@@ -136,7 +125,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, ...@@ -136,7 +125,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
/* card->num_links includes Codec */ /* card->num_links includes Codec */
asoc_simple_card_canonicalize_cpu(dai_link, asoc_simple_card_canonicalize_cpu(dai_link,
(card->num_links - 1) == 1); of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else { } else {
/* FE is dummy */ /* FE is dummy */
dai_link->cpu_of_node = NULL; dai_link->cpu_of_node = NULL;
...@@ -167,11 +156,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, ...@@ -167,11 +156,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
"prefix"); "prefix");
} }
ret = snd_soc_of_parse_tdm_slot(ep, ret = asoc_simple_card_of_parse_tdm(ep, dai_props);
&dai_props->tx_slot_mask,
&dai_props->rx_slot_mask,
&dai_props->slots,
&dai_props->slot_width);
if (ret) if (ret)
return ret; return ret;
...@@ -198,6 +183,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -198,6 +183,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct device_node *cpu_ep; struct device_node *cpu_ep;
struct device_node *codec_ep; struct device_node *codec_ep;
struct device_node *rcpu_ep; struct device_node *rcpu_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
unsigned int daifmt = 0; unsigned int daifmt = 0;
int dai_idx, ret; int dai_idx, ret;
int rc, codec; int rc, codec;
...@@ -210,15 +197,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -210,15 +197,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
* see simple-card * see simple-card
*/ */
ret = snd_soc_of_parse_audio_routing(card, "routing"); ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
if (ret) if (ret < 0)
return ret; return ret;
/* sampling rate convert */ asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
of_property_read_u32(node, "convert-rate", &priv->convert_rate);
/* channels transfer */
of_property_read_u32(node, "convert-channels", &priv->convert_channels);
/* /*
* it supports multi CPU, single CODEC only here * it supports multi CPU, single CODEC only here
...@@ -254,6 +237,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -254,6 +237,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
} }
dai_idx = 0; dai_idx = 0;
codec_port_old = NULL;
for (codec = 0; codec < 2; codec++) { for (codec = 0; codec < 2; codec++) {
/* /*
* To listup valid sounds continuously, * To listup valid sounds continuously,
...@@ -264,15 +248,22 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -264,15 +248,22 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
cpu_port = it.node; cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL); cpu_ep = of_get_next_child(cpu_port, NULL);
codec_ep = of_graph_get_remote_endpoint(cpu_ep); codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_graph_get_port_parent(codec_ep);
of_node_put(cpu_port); of_node_put(cpu_port);
of_node_put(cpu_ep); of_node_put(cpu_ep);
of_node_put(codec_ep); of_node_put(codec_ep);
of_node_put(codec_port);
if (codec) { if (codec) {
if (!codec_ep) if (!codec_port)
continue; continue;
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
/* Back-End (= Codec) */ /* Back-End (= Codec) */
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0); ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
if (ret < 0) if (ret < 0)
...@@ -290,9 +281,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) ...@@ -290,9 +281,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret) if (ret)
goto parse_of_err; goto parse_of_err;
dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
ret = 0; ret = 0;
parse_of_err: parse_of_err:
...@@ -306,22 +294,34 @@ static int asoc_graph_get_dais_count(struct device *dev) ...@@ -306,22 +294,34 @@ static int asoc_graph_get_dais_count(struct device *dev)
struct device_node *cpu_port; struct device_node *cpu_port;
struct device_node *cpu_ep; struct device_node *cpu_ep;
struct device_node *codec_ep; struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
int count = 0; int count = 0;
int rc; int rc;
codec_port_old = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node; cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL); cpu_ep = of_get_next_child(cpu_port, NULL);
codec_ep = of_graph_get_remote_endpoint(cpu_ep); codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_graph_get_port_parent(codec_ep);
of_node_put(cpu_port); of_node_put(cpu_port);
of_node_put(cpu_ep); of_node_put(cpu_ep);
of_node_put(codec_ep); of_node_put(codec_ep);
of_node_put(codec_port);
if (cpu_ep) if (cpu_ep)
count++; count++;
if (codec_ep)
count++; if (!codec_port)
continue;
if (codec_port_old == codec_port)
continue;
count++;
codec_port_old = codec_port;
} }
return count; return count;
......
...@@ -13,6 +13,46 @@ ...@@ -13,6 +13,46 @@
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <sound/simple_card_utils.h> #include <sound/simple_card_utils.h>
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (data->convert_rate)
rate->min =
rate->max = data->convert_rate;
if (data->convert_channels)
channels->min =
channels->max = data->convert_channels;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
struct asoc_simple_card_data *data)
{
struct device_node *np = dev->of_node;
char prop[128];
if (!prefix)
prefix = "";
/* sampling rate convert */
snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
of_property_read_u32(np, prop, &data->convert_rate);
/* channels transfer */
snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
of_property_read_u32(np, prop, &data->convert_channels);
dev_dbg(dev, "convert_rate %d\n", data->convert_rate);
dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert);
int asoc_simple_card_parse_daifmt(struct device *dev, int asoc_simple_card_parse_daifmt(struct device *dev,
struct device_node *node, struct device_node *node,
struct device_node *codec, struct device_node *codec,
...@@ -110,6 +150,24 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, ...@@ -110,6 +150,24 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
} }
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
struct clk *clk)
{
dai->clk = clk;
}
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
{
return clk_prepare_enable(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
{
clk_disable_unprepare(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
int asoc_simple_card_parse_clk(struct device *dev, int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node, struct device_node *node,
struct device_node *dai_of_node, struct device_node *dai_of_node,
...@@ -128,7 +186,8 @@ int asoc_simple_card_parse_clk(struct device *dev, ...@@ -128,7 +186,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
clk = devm_get_clk_from_child(dev, node, NULL); clk = devm_get_clk_from_child(dev, node, NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk); simple_dai->sysclk = clk_get_rate(clk);
simple_dai->clk = clk;
asoc_simple_card_clk_register(simple_dai, clk);
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val; simple_dai->sysclk = val;
} else { } else {
...@@ -316,6 +375,47 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) ...@@ -316,6 +375,47 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
} }
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
char *prefix,
int optional)
{
struct device_node *node = card->dev->of_node;
char prop[128];
if (!prefix)
prefix = "";
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
if (!of_property_read_bool(node, prop)) {
if (optional)
return 0;
return -EINVAL;
}
return snd_soc_of_parse_audio_routing(card, prop);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing);
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
char *prefix)
{
struct device_node *node = card->dev->of_node;
char prop[128];
if (!prefix)
prefix = "";
snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
if (of_property_read_bool(node, prop))
return snd_soc_of_parse_audio_simple_widgets(card, prop);
/* no widgets is not error */
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
/* Module information */ /* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
......
...@@ -118,13 +118,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) ...@@ -118,13 +118,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
int ret; int ret;
ret = clk_prepare_enable(dai_props->cpu_dai.clk); ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(dai_props->codec_dai.clk); ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
if (ret) if (ret)
clk_disable_unprepare(dai_props->cpu_dai.clk); asoc_simple_card_clk_disable(&dai_props->cpu_dai);
return ret; return ret;
} }
...@@ -136,9 +136,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) ...@@ -136,9 +136,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props = struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
clk_disable_unprepare(dai_props->cpu_dai.clk); asoc_simple_card_clk_disable(&dai_props->cpu_dai);
clk_disable_unprepare(dai_props->codec_dai.clk); asoc_simple_card_clk_disable(&dai_props->codec_dai);
} }
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
...@@ -233,13 +233,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ...@@ -233,13 +233,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
snprintf(prop, sizeof(prop), "%scpu", prefix); snprintf(prop, sizeof(prop), "%scpu", prefix);
cpu = of_get_child_by_name(node, prop); cpu = of_get_child_by_name(node, prop);
if (!cpu) {
ret = -EINVAL;
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
goto dai_link_of_err;
}
snprintf(prop, sizeof(prop), "%splat", prefix); snprintf(prop, sizeof(prop), "%splat", prefix);
plat = of_get_child_by_name(node, prop); plat = of_get_child_by_name(node, prop);
snprintf(prop, sizeof(prop), "%scodec", prefix); snprintf(prop, sizeof(prop), "%scodec", prefix);
codec = of_get_child_by_name(node, prop); codec = of_get_child_by_name(node, prop);
if (!cpu || !codec) { if (!codec) {
ret = -EINVAL; ret = -EINVAL;
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
goto dai_link_of_err; goto dai_link_of_err;
...@@ -265,17 +271,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ...@@ -265,17 +271,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask, ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
&cpu_dai->rx_slot_mask,
&cpu_dai->slots,
&cpu_dai->slot_width);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask, ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
&codec_dai->rx_slot_mask,
&codec_dai->slots,
&codec_dai->slot_width);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
...@@ -341,12 +341,12 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, ...@@ -341,12 +341,12 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
return 0; return 0;
} }
static int asoc_simple_card_parse_of(struct device_node *node, static int asoc_simple_card_parse_of(struct simple_card_data *priv)
struct simple_card_data *priv)
{ {
struct device *dev = simple_priv_to_dev(priv); struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *dai_link; struct device_node *dai_link;
struct device_node *node = dev->of_node;
int ret; int ret;
if (!node) if (!node)
...@@ -354,21 +354,13 @@ static int asoc_simple_card_parse_of(struct device_node *node, ...@@ -354,21 +354,13 @@ static int asoc_simple_card_parse_of(struct device_node *node,
dai_link = of_get_child_by_name(node, PREFIX "dai-link"); dai_link = of_get_child_by_name(node, PREFIX "dai-link");
/* The off-codec widgets */ ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (of_property_read_bool(node, PREFIX "widgets")) { if (ret < 0)
ret = snd_soc_of_parse_audio_simple_widgets(card, goto card_parse_end;
PREFIX "widgets");
if (ret)
goto card_parse_end;
}
/* DAPM routes */ ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
if (of_property_read_bool(node, PREFIX "routing")) { if (ret < 0)
ret = snd_soc_of_parse_audio_routing(card, goto card_parse_end;
PREFIX "routing");
if (ret)
goto card_parse_end;
}
/* Factor to mclk, used in hw_params() */ /* Factor to mclk, used in hw_params() */
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
...@@ -445,7 +437,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ...@@ -445,7 +437,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (np && of_device_is_available(np)) { if (np && of_device_is_available(np)) {
ret = asoc_simple_card_parse_of(np, priv); ret = asoc_simple_card_parse_of(priv);
if (ret < 0) { if (ret < 0) {
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret); dev_err(dev, "parse error %d\n", ret);
......
...@@ -27,8 +27,7 @@ struct simple_card_data { ...@@ -27,8 +27,7 @@ struct simple_card_data {
struct snd_soc_codec_conf codec_conf; struct snd_soc_codec_conf codec_conf;
struct asoc_simple_dai *dai_props; struct asoc_simple_dai *dai_props;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
u32 convert_rate; struct asoc_simple_card_data adata;
u32 convert_channels;
}; };
#define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_card(priv) (&(priv)->snd_card)
...@@ -47,7 +46,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) ...@@ -47,7 +46,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct asoc_simple_dai *dai_props = struct asoc_simple_dai *dai_props =
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
return clk_prepare_enable(dai_props->clk); return asoc_simple_card_clk_enable(dai_props);
} }
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
...@@ -57,7 +56,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) ...@@ -57,7 +56,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct asoc_simple_dai *dai_props = struct asoc_simple_dai *dai_props =
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
clk_disable_unprepare(dai_props->clk); asoc_simple_card_clk_disable(dai_props);
} }
static const struct snd_soc_ops asoc_simple_card_ops = { static const struct snd_soc_ops asoc_simple_card_ops = {
...@@ -86,18 +85,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -86,18 +85,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (priv->convert_rate) asoc_simple_card_convert_fixup(&priv->adata, params);
rate->min =
rate->max = priv->convert_rate;
if (priv->convert_channels)
channels->min =
channels->max = priv->convert_channels;
return 0; return 0;
} }
...@@ -171,11 +160,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, ...@@ -171,11 +160,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
PREFIX "prefix"); PREFIX "prefix");
} }
ret = snd_soc_of_parse_tdm_slot(np, ret = asoc_simple_card_of_parse_tdm(np, dai_props);
&dai_props->tx_slot_mask,
&dai_props->rx_slot_mask,
&dai_props->slots,
&dai_props->slot_width);
if (ret) if (ret)
return ret; return ret;
...@@ -206,15 +191,11 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) ...@@ -206,15 +191,11 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
if (!node) if (!node)
return -EINVAL; return -EINVAL;
ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing"); ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* sampling rate convert */ asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
/* channels transfer */
of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
/* find 1st codec */ /* find 1st codec */
np = of_get_child_by_name(node, PREFIX "codec"); np = of_get_child_by_name(node, PREFIX "codec");
...@@ -241,9 +222,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) ...@@ -241,9 +222,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
return 0; return 0;
} }
......
...@@ -97,8 +97,8 @@ static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg) ...@@ -97,8 +97,8 @@ static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg)
return readl(i2s->base + reg); return readl(i2s->base + reg);
} }
int hi6210_i2s_startup(struct snd_pcm_substream *substream, static int hi6210_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai) struct snd_soc_dai *cpu_dai)
{ {
struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
int ret, n; int ret, n;
...@@ -175,8 +175,9 @@ int hi6210_i2s_startup(struct snd_pcm_substream *substream, ...@@ -175,8 +175,9 @@ int hi6210_i2s_startup(struct snd_pcm_substream *substream,
return 0; return 0;
} }
void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai) static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{ {
struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
int n; int n;
...@@ -524,7 +525,7 @@ static struct snd_soc_dai_ops hi6210_i2s_dai_ops = { ...@@ -524,7 +525,7 @@ static struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
.shutdown = hi6210_i2s_shutdown, .shutdown = hi6210_i2s_shutdown,
}; };
struct snd_soc_dai_driver hi6210_i2s_dai_init = { static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
.probe = hi6210_i2s_dai_probe, .probe = hi6210_i2s_dai_probe,
.playback = { .playback = {
.channels_min = 2, .channels_min = 2,
......
...@@ -107,7 +107,7 @@ static const struct snd_kcontrol_new mt2701_cs42448_controls[] = { ...@@ -107,7 +107,7 @@ static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
static const unsigned int mt2701_cs42448_sampling_rates[] = {48000}; static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = { static const struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates), .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
.list = mt2701_cs42448_sampling_rates, .list = mt2701_cs42448_sampling_rates,
.mask = 0, .mask = 0,
......
...@@ -835,15 +835,11 @@ static ssize_t dma_op_mode_store(struct device *dev, ...@@ -835,15 +835,11 @@ static ssize_t dma_op_mode_store(struct device *dev,
const char *buf, size_t size) const char *buf, size_t size)
{ {
struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
const char * const *s; int i;
int i = 0;
for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
if (sysfs_streq(buf, *s))
break;
if (i == ARRAY_SIZE(dma_op_modes)) i = sysfs_match_string(dma_op_modes, buf);
return -EINVAL; if (i < 0)
return i;
spin_lock_irq(&mcbsp->lock); spin_lock_irq(&mcbsp->lock);
if (!mcbsp->free) { if (!mcbsp->free) {
......
config SND_PXA2XX_SOC config SND_PXA2XX_SOC
tristate "SoC Audio for the Intel PXA2xx chip" tristate "SoC Audio for the Intel PXA2xx chip"
depends on ARCH_PXA depends on ARCH_PXA || COMPILE_TEST
select SND_PXA2XX_LIB select SND_PXA2XX_LIB
help help
Say Y or M if you want to add support for codecs attached to Say Y or M if you want to add support for codecs attached to
......
...@@ -15,6 +15,15 @@ config SND_SOC_ROCKCHIP_I2S ...@@ -15,6 +15,15 @@ config SND_SOC_ROCKCHIP_I2S
Rockchip I2S device. The device supports upto maximum of Rockchip I2S device. The device supports upto maximum of
8 channels each for play and record. 8 channels each for play and record.
config SND_SOC_ROCKCHIP_PDM
tristate "Rockchip PDM Controller Driver"
depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for PDM driver for
Rockchip PDM Controller. The Controller supports up to maximum of
8 channels record.
config SND_SOC_ROCKCHIP_SPDIF config SND_SOC_ROCKCHIP_SPDIF
tristate "Rockchip SPDIF Device Driver" tristate "Rockchip SPDIF Device Driver"
depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
......
# ROCKCHIP Platform Support # ROCKCHIP Platform Support
snd-soc-rockchip-i2s-objs := rockchip_i2s.o snd-soc-rockchip-i2s-objs := rockchip_i2s.o
snd-soc-rockchip-pdm-objs := rockchip_pdm.o
snd-soc-rockchip-spdif-objs := rockchip_spdif.o snd-soc-rockchip-spdif-objs := rockchip_spdif.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
snd-soc-rockchip-max98090-objs := rockchip_max98090.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o
......
...@@ -206,7 +206,21 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -206,7 +206,21 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
mask = I2S_TXCR_IBM_MASK; mask = I2S_CKR_CKP_MASK;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
val = I2S_CKR_CKP_NEG;
break;
case SND_SOC_DAIFMT_IB_NF:
val = I2S_CKR_CKP_POS;
break;
default:
return -EINVAL;
}
regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_RIGHT_J:
val = I2S_TXCR_IBM_RSJM; val = I2S_TXCR_IBM_RSJM;
...@@ -217,13 +231,19 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -217,13 +231,19 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
val = I2S_TXCR_IBM_NORMAL; val = I2S_TXCR_IBM_NORMAL;
break; break;
case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */
val = I2S_TXCR_TFS_PCM;
break;
case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */
val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val); regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val);
mask = I2S_RXCR_IBM_MASK; mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_RIGHT_J:
val = I2S_RXCR_IBM_RSJM; val = I2S_RXCR_IBM_RSJM;
...@@ -234,6 +254,12 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -234,6 +254,12 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
val = I2S_RXCR_IBM_NORMAL; val = I2S_RXCR_IBM_NORMAL;
break; break;
case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */
val = I2S_RXCR_TFS_PCM;
break;
case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */
val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -617,12 +643,13 @@ static int rockchip_i2s_probe(struct platform_device *pdev) ...@@ -617,12 +643,13 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_pm_disable; goto err_pm_disable;
} }
soc_dai = devm_kzalloc(&pdev->dev, soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai,
sizeof(*soc_dai), GFP_KERNEL); sizeof(*soc_dai), GFP_KERNEL);
if (!soc_dai) if (!soc_dai) {
return -ENOMEM; ret = -ENOMEM;
goto err_pm_disable;
}
memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai));
if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
if (val >= 2 && val <= 8) if (val >= 2 && val <= 8)
soc_dai->playback.channels_max = val; soc_dai->playback.channels_max = val;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#define I2S_TXCR_TFS_SHIFT 5 #define I2S_TXCR_TFS_SHIFT 5
#define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT) #define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT) #define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_TFS_MASK (1 << I2S_TXCR_TFS_SHIFT)
#define I2S_TXCR_VDW_SHIFT 0 #define I2S_TXCR_VDW_SHIFT 0
#define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT) #define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT)
#define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT) #define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT)
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
#define I2S_RXCR_TFS_SHIFT 5 #define I2S_RXCR_TFS_SHIFT 5
#define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT) #define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT) #define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_TFS_MASK (1 << I2S_RXCR_TFS_SHIFT)
#define I2S_RXCR_VDW_SHIFT 0 #define I2S_RXCR_VDW_SHIFT 0
#define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT) #define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT)
#define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT) #define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT)
...@@ -91,6 +93,7 @@ ...@@ -91,6 +93,7 @@
#define I2S_CKR_CKP_SHIFT 26 #define I2S_CKR_CKP_SHIFT 26
#define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT) #define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT)
#define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT) #define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT)
#define I2S_CKR_CKP_MASK (1 << I2S_CKR_CKP_SHIFT)
#define I2S_CKR_RLP_SHIFT 25 #define I2S_CKR_RLP_SHIFT 25
#define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT) #define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT)
#define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT) #define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT)
......
This diff is collapsed.
/*
* Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _ROCKCHIP_PDM_H
#define _ROCKCHIP_PDM_H
/* PDM REGS */
#define PDM_SYSCONFIG (0x0000)
#define PDM_CTRL0 (0x0004)
#define PDM_CTRL1 (0x0008)
#define PDM_CLK_CTRL (0x000c)
#define PDM_HPF_CTRL (0x0010)
#define PDM_FIFO_CTRL (0x0014)
#define PDM_DMA_CTRL (0x0018)
#define PDM_INT_EN (0x001c)
#define PDM_INT_CLR (0x0020)
#define PDM_INT_ST (0x0024)
#define PDM_RXFIFO_DATA (0x0030)
#define PDM_DATA_VALID (0x0054)
#define PDM_VERSION (0x0058)
/* PDM_SYSCONFIG */
#define PDM_RX_MASK (0x1 << 2)
#define PDM_RX_START (0x1 << 2)
#define PDM_RX_STOP (0x0 << 2)
#define PDM_RX_CLR_MASK (0x1 << 0)
#define PDM_RX_CLR_WR (0x1 << 0)
#define PDM_RX_CLR_DONE (0x0 << 0)
/* PDM CTRL0 */
#define PDM_PATH_MSK (0xf << 27)
#define PDM_PATH3_EN BIT(30)
#define PDM_PATH2_EN BIT(29)
#define PDM_PATH1_EN BIT(28)
#define PDM_PATH0_EN BIT(27)
#define PDM_HWT_EN BIT(26)
#define PDM_VDW_MSK (0x1f << 0)
#define PDM_VDW(X) ((X - 1) << 0)
/* PDM CLK CTRL */
#define PDM_CLK_MSK BIT(5)
#define PDM_CLK_EN BIT(5)
#define PDM_CLK_DIS (0x0 << 5)
#define PDM_CKP_MSK BIT(3)
#define PDM_CKP_NORMAL (0x0 << 3)
#define PDM_CKP_INVERTED BIT(3)
#define PDM_DS_RATIO_MSK (0x7 << 0)
#define PDM_CLK_320FS (0x0 << 0)
#define PDM_CLK_640FS (0x1 << 0)
#define PDM_CLK_1280FS (0x2 << 0)
#define PDM_CLK_2560FS (0x3 << 0)
#define PDM_CLK_5120FS (0x4 << 0)
/* PDM HPF CTRL */
#define PDM_HPF_LE BIT(3)
#define PDM_HPF_RE BIT(2)
#define PDM_HPF_CF_MSK (0x3 << 0)
#define PDM_HPF_3P79HZ (0x0 << 0)
#define PDM_HPF_60HZ (0x1 << 0)
#define PDM_HPF_243HZ (0x2 << 0)
#define PDM_HPF_493HZ (0x3 << 0)
/* PDM DMA CTRL */
#define PDM_DMA_RD_MSK BIT(8)
#define PDM_DMA_RD_EN BIT(8)
#define PDM_DMA_RD_DIS (0x0 << 8)
#define PDM_DMA_RDL_MSK (0x7f << 0)
#define PDM_DMA_RDL(X) ((X - 1) << 0)
#endif /* _ROCKCHIP_PDM_H */
...@@ -49,8 +49,12 @@ static const struct of_device_id rk_spdif_match[] = { ...@@ -49,8 +49,12 @@ static const struct of_device_id rk_spdif_match[] = {
.data = (void *)RK_SPDIF_RK3066 }, .data = (void *)RK_SPDIF_RK3066 },
{ .compatible = "rockchip,rk3188-spdif", { .compatible = "rockchip,rk3188-spdif",
.data = (void *)RK_SPDIF_RK3188 }, .data = (void *)RK_SPDIF_RK3188 },
{ .compatible = "rockchip,rk3228-spdif",
.data = (void *)RK_SPDIF_RK3366 },
{ .compatible = "rockchip,rk3288-spdif", { .compatible = "rockchip,rk3288-spdif",
.data = (void *)RK_SPDIF_RK3288 }, .data = (void *)RK_SPDIF_RK3288 },
{ .compatible = "rockchip,rk3328-spdif",
.data = (void *)RK_SPDIF_RK3366 },
{ .compatible = "rockchip,rk3366-spdif", { .compatible = "rockchip,rk3366-spdif",
.data = (void *)RK_SPDIF_RK3366 }, .data = (void *)RK_SPDIF_RK3366 },
{ .compatible = "rockchip,rk3368-spdif", { .compatible = "rockchip,rk3368-spdif",
......
...@@ -44,7 +44,7 @@ struct s3c24xx_uda134x { ...@@ -44,7 +44,7 @@ struct s3c24xx_uda134x {
static unsigned int rates[33 * 2]; static unsigned int rates[33 * 2];
#ifdef ENFORCE_RATES #ifdef ENFORCE_RATES
static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
.count = ARRAY_SIZE(rates), .count = ARRAY_SIZE(rates),
.list = rates, .list = rates,
.mask = 0, .mask = 0,
......
...@@ -301,7 +301,12 @@ struct fsi_master { ...@@ -301,7 +301,12 @@ struct fsi_master {
spinlock_t lock; spinlock_t lock;
}; };
static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io); static inline int fsi_stream_is_play(struct fsi_priv *fsi,
struct fsi_stream *io)
{
return &fsi->playback == io;
}
/* /*
* basic read write function * basic read write function
...@@ -489,12 +494,6 @@ static void fsi_count_fifo_err(struct fsi_priv *fsi) ...@@ -489,12 +494,6 @@ static void fsi_count_fifo_err(struct fsi_priv *fsi)
/* /*
* fsi_stream_xx() function * fsi_stream_xx() function
*/ */
static inline int fsi_stream_is_play(struct fsi_priv *fsi,
struct fsi_stream *io)
{
return &fsi->playback == io;
}
static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
......
...@@ -352,6 +352,17 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, ...@@ -352,6 +352,17 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
return 0; return 0;
} }
/* optionally pass new dynamic widget to component driver. This is mainly for
* external widgets where we can assign private data/ops */
static int soc_tplg_widget_ready(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
if (tplg->comp && tplg->ops && tplg->ops->widget_ready)
return tplg->ops->widget_ready(tplg->comp, w, tplg_w);
return 0;
}
/* pass DAI configurations to component driver for extra initialization */ /* pass DAI configurations to component driver for extra initialization */
static int soc_tplg_dai_load(struct soc_tplg *tplg, static int soc_tplg_dai_load(struct soc_tplg *tplg,
struct snd_soc_dai_driver *dai_drv) struct snd_soc_dai_driver *dai_drv)
...@@ -1160,7 +1171,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, ...@@ -1160,7 +1171,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
return -EINVAL; return -EINVAL;
} }
dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count); dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count,
hdr->index);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
...@@ -1473,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ...@@ -1473,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
if (template.id < 0) if (template.id < 0)
return template.id; return template.id;
/* strings are allocated here, but used and freed by the widget */
template.name = kstrdup(w->name, GFP_KERNEL); template.name = kstrdup(w->name, GFP_KERNEL);
if (!template.name) if (!template.name)
return -ENOMEM; return -ENOMEM;
...@@ -1585,11 +1598,17 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ...@@ -1585,11 +1598,17 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
widget->dobj.widget.kcontrol_type = kcontrol_type; widget->dobj.widget.kcontrol_type = kcontrol_type;
widget->dobj.ops = tplg->ops; widget->dobj.ops = tplg->ops;
widget->dobj.index = tplg->index; widget->dobj.index = tplg->index;
kfree(template.sname);
kfree(template.name);
list_add(&widget->dobj.list, &tplg->comp->dobj_list); list_add(&widget->dobj.list, &tplg->comp->dobj_list);
ret = soc_tplg_widget_ready(tplg, widget, w);
if (ret < 0)
goto ready_err;
return 0; return 0;
ready_err:
snd_soc_tplg_widget_remove(widget);
snd_soc_dapm_free_widget(widget);
hdr_err: hdr_err:
kfree(template.sname); kfree(template.sname);
err: err:
...@@ -1636,7 +1655,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) ...@@ -1636,7 +1655,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
*/ */
if (!card || !card->instantiated) { if (!card || !card->instantiated) {
dev_warn(tplg->dev, "ASoC: Parent card not yet available," dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
"Do not add new widgets now\n"); " widget card binding deferred\n");
return 0; return 0;
} }
...@@ -2371,7 +2390,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, ...@@ -2371,7 +2390,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
/* check for matching ID */ /* check for matching ID */
if (hdr->index != tplg->req_index && if (hdr->index != tplg->req_index &&
hdr->index != SND_SOC_TPLG_INDEX_ALL) tplg->req_index != SND_SOC_TPLG_INDEX_ALL)
return 0; return 0;
tplg->index = hdr->index; tplg->index = hdr->index;
......
menuconfig SND_SOC_STM32 menu "STMicroelectronics STM32 SOC audio support"
tristate "STMicroelectronics STM32 SOC audio support"
config SND_SOC_STM32_SAI
tristate "STM32 SAI interface (Serial Audio Interface) support"
depends on ARCH_STM32 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO select REGMAP_MMIO
help help
Say Y if you want to enable ASoC-support for STM32 Say Y if you want to enable SAI for STM32
config SND_SOC_STM32_I2S
tristate "STM32 I2S interface (SPI/I2S block) support"
depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
Say Y if you want to enable I2S for STM32
config SND_SOC_STM32_SPDIFRX
tristate "STM32 S/PDIF receiver (SPDIFRX) support"
depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
select SND_SOC_SPDIF
help
Say Y if you want to enable S/PDIF capture for STM32
endmenu
# SAI # SAI
snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o
snd-soc-stm32-sai-objs := stm32_sai.o snd-soc-stm32-sai-objs := stm32_sai.o
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o
# I2S
snd-soc-stm32-i2s-objs := stm32_i2s.o
obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o
# SPDIFRX
snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o
obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o
This diff is collapsed.
...@@ -27,8 +27,17 @@ ...@@ -27,8 +27,17 @@
#include "stm32_sai.h" #include "stm32_sai.h"
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4,
};
static const struct stm32_sai_conf stm32_sai_conf_h7 = {
.version = SAI_STM32H7,
};
static const struct of_device_id stm32_sai_ids[] = { static const struct of_device_id stm32_sai_ids[] = {
{ .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
{ .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
{} {}
}; };
...@@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev) ...@@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
of_id = of_match_device(stm32_sai_ids, &pdev->dev); of_id = of_match_device(stm32_sai_ids, &pdev->dev);
if (of_id) if (of_id)
sai->version = (enum stm32_sai_version)of_id->data; sai->conf = (struct stm32_sai_conf *)of_id->data;
else else
return -EINVAL; return -EINVAL;
...@@ -110,6 +119,6 @@ static struct platform_driver stm32_sai_driver = { ...@@ -110,6 +119,6 @@ static struct platform_driver stm32_sai_driver = {
module_platform_driver(stm32_sai_driver); module_platform_driver(stm32_sai_driver);
MODULE_DESCRIPTION("STM32 Soc SAI Interface"); MODULE_DESCRIPTION("STM32 Soc SAI Interface");
MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
MODULE_ALIAS("platform:st,stm32-sai"); MODULE_ALIAS("platform:st,stm32-sai");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment