mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
Merge branch 'asoc-5.4' into asoc-next
This commit is contained in:
commit
bb83178611
88
Documentation/devicetree/bindings/dsp/fsl,dsp.yaml
Normal file
88
Documentation/devicetree/bindings/dsp/fsl,dsp.yaml
Normal file
@ -0,0 +1,88 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dsp/fsl,dsp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX8 DSP core
|
||||
|
||||
maintainers:
|
||||
- Daniel Baluta <daniel.baluta@nxp.com>
|
||||
|
||||
description: |
|
||||
Some boards from i.MX8 family contain a DSP core used for
|
||||
advanced pre- and post- audio processing.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8qxp-dsp
|
||||
|
||||
reg:
|
||||
description: Should contain register location and length
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: ipg clock
|
||||
- description: ocram clock
|
||||
- description: core clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ipg
|
||||
- const: ocram
|
||||
- const: core
|
||||
|
||||
power-domains:
|
||||
description:
|
||||
List of phandle and PM domain specifier as documented in
|
||||
Documentation/devicetree/bindings/power/power_domain.txt
|
||||
maxItems: 4
|
||||
|
||||
mboxes:
|
||||
description:
|
||||
List of <&phandle type channel> - 2 channels for TXDB, 2 channels for RXDB
|
||||
(see mailbox/fsl,mu.txt)
|
||||
maxItems: 4
|
||||
|
||||
mbox-names:
|
||||
items:
|
||||
- const: txdb0
|
||||
- const: txdb1
|
||||
- const: rxdb0
|
||||
- const: rxdb1
|
||||
|
||||
memory-region:
|
||||
description:
|
||||
phandle to a node describing reserved memory (System RAM memory)
|
||||
used by DSP (see bindings/reserved-memory/reserved-memory.txt)
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- mboxes
|
||||
- mbox-names
|
||||
- memory-region
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <dt-bindings/clock/imx8-clock.h>
|
||||
dsp@596e8000 {
|
||||
compatible = "fsl,imx8qxp-dsp";
|
||||
reg = <0x596e8000 0x88000>;
|
||||
clocks = <&adma_lpcg IMX_ADMA_LPCG_DSP_IPG_CLK>,
|
||||
<&adma_lpcg IMX_ADMA_LPCG_OCRAM_IPG_CLK>,
|
||||
<&adma_lpcg IMX_ADMA_LPCG_DSP_CORE_CLK>;
|
||||
clock-names = "ipg", "ocram", "core";
|
||||
power-domains = <&pd IMX_SC_R_MU_13A>,
|
||||
<&pd IMX_SC_R_MU_13B>,
|
||||
<&pd IMX_SC_R_DSP>,
|
||||
<&pd IMX_SC_R_DSP_RAM>;
|
||||
mbox-names = "txdb0", "txdb1", "rxdb0", "rxdb1";
|
||||
mboxes = <&lsio_mu13 2 0>, <&lsio_mu13 2 1>, <&lsio_mu13 3 0>, <&lsio_mu13 3 1>;
|
||||
};
|
@ -70,7 +70,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun8i-h3-spdif
|
||||
enum:
|
||||
- allwinner,sun8i-h3-spdif
|
||||
- allwinner,sun50i-h6-spdif
|
||||
|
||||
then:
|
||||
properties:
|
||||
|
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/allwinner,sun50i-a64-codec-analog.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A64 Analog Codec Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: allwinner,sun50i-a64-codec-analog
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
cpvdd-supply:
|
||||
description:
|
||||
Regulator for the headphone amplifier
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- cpvdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
cpvdd-supply = <®_eldo1>;
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/allwinner,sun8i-a33-codec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A33 Codec Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
|
||||
properties:
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
const: allwinner,sun8i-a33-codec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Module Clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: mod
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
audio-codec@1c22e00 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a33-codec";
|
||||
reg = <0x01c22e00 0x400>;
|
||||
interrupts = <0 29 4>;
|
||||
clocks = <&ccu 47>, <&ccu 92>;
|
||||
clock-names = "bus", "mod";
|
||||
};
|
||||
|
||||
...
|
@ -4,13 +4,18 @@ Required properties:
|
||||
- compatible: 'amlogic,axg-toddr' or
|
||||
'amlogic,axg-toddr' or
|
||||
'amlogic,g12a-frddr' or
|
||||
'amlogic,g12a-toddr'
|
||||
'amlogic,g12a-toddr' or
|
||||
'amlogic,sm1-frddr' or
|
||||
'amlogic,sm1-toddr'
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- interrupts: interrupt specifier for the fifo.
|
||||
- clocks: phandle to the fifo peripheral clock provided by the audio
|
||||
clock controller.
|
||||
- resets: phandle to memory ARB line provided by the arb reset controller.
|
||||
- resets: list of reset phandle, one for each entry reset-names.
|
||||
- reset-names: should contain the following:
|
||||
* "arb" : memory ARB line (required)
|
||||
* "rst" : dedicated device reset line (optional)
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Example of FRDDR A on the A113 SoC:
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-pdm' or
|
||||
'amlogic,g12a-pdm'
|
||||
'amlogic,g12a-pdm' or
|
||||
'amlogic,sm1-pdm'
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
@ -12,6 +13,9 @@ Required properties:
|
||||
* "sysclk" : dsp system clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Optional property:
|
||||
- resets: phandle to the dedicated reset line of the pdm input.
|
||||
|
||||
Example of PDM on the A113 SoC:
|
||||
|
||||
pdm: audio-controller@ff632000 {
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-spdifin' or
|
||||
'amlogic,g12a-spdifin'
|
||||
'amlogic,g12a-spdifin' or
|
||||
'amlogic,sm1-spdifin'
|
||||
- interrupts: interrupt specifier for the spdif input.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
@ -10,6 +11,9 @@ Required properties:
|
||||
* "refclk" : spdif input reference clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Optional property:
|
||||
- resets: phandle to the dedicated reset line of the spdif input.
|
||||
|
||||
Example on the A113 SoC:
|
||||
|
||||
spdifin: audio-controller@400 {
|
||||
|
@ -2,13 +2,17 @@
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-spdifout' or
|
||||
'amlogic,g12a-spdifout'
|
||||
'amlogic,g12a-spdifout' or
|
||||
'amlogic,sm1-spdifout'
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
* "pclk" : peripheral clock.
|
||||
* "mclk" : master clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Optional property:
|
||||
- resets: phandle to the dedicated reset line of the spdif output.
|
||||
|
||||
Example on the A113 SoC:
|
||||
|
||||
spdifout: audio-controller@480 {
|
||||
|
@ -4,7 +4,9 @@ Required properties:
|
||||
- compatible: 'amlogic,axg-tdmin' or
|
||||
'amlogic,axg-tdmout' or
|
||||
'amlogic,g12a-tdmin' or
|
||||
'amlogic,g12a-tdmout'
|
||||
'amlogic,g12a-tdmout' or
|
||||
'amlogic,sm1-tdmin' or
|
||||
'amlogic,sm1-tdmout
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
|
@ -1,10 +1,12 @@
|
||||
* Amlogic HDMI Tx control glue
|
||||
|
||||
Required properties:
|
||||
- compatible: "amlogic,g12a-tohdmitx"
|
||||
- compatible: "amlogic,g12a-tohdmitx" or
|
||||
"amlogic,sm1-tohdmitx"
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- #sound-dai-cells: should be 1.
|
||||
- resets: phandle to the dedicated reset line of the hdmitx glue.
|
||||
|
||||
Example on the S905X2 SoC:
|
||||
|
||||
@ -12,6 +14,7 @@ tohdmitx: audio-controller@744 {
|
||||
compatible = "amlogic,g12a-tohdmitx";
|
||||
reg = <0x0 0x744 0x0 0x4>;
|
||||
#sound-dai-cells = <1>;
|
||||
resets = <&clkc_audio AUD_RESET_TOHDMITX>;
|
||||
};
|
||||
|
||||
Example of an 'amlogic,axg-sound-card':
|
||||
|
23
Documentation/devicetree/bindings/sound/everest,es8316.txt
Normal file
23
Documentation/devicetree/bindings/sound/everest,es8316.txt
Normal file
@ -0,0 +1,23 @@
|
||||
Everest ES8316 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "everest,es8316"
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks : a list of phandle, should contain entries for clock-names
|
||||
- clock-names : should include as follows:
|
||||
"mclk" : master clock (MCLK) of the device
|
||||
|
||||
Example:
|
||||
|
||||
es8316: codec@11 {
|
||||
compatible = "everest,es8316";
|
||||
reg = <0x11>;
|
||||
clocks = <&clks 10>;
|
||||
clock-names = "mclk";
|
||||
};
|
@ -7,8 +7,11 @@ other DSPs. It has up to six transmitters and four receivers.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Compatible list, must contain "fsl,imx35-esai" or
|
||||
"fsl,vf610-esai"
|
||||
- compatible : Compatible list, should contain one of the following
|
||||
compatibles:
|
||||
"fsl,imx35-esai",
|
||||
"fsl,vf610-esai",
|
||||
"fsl,imx6ull-esai",
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
|
@ -8,7 +8,9 @@ codec/DSP interfaces.
|
||||
Required properties:
|
||||
|
||||
- compatible : Compatible list, contains "fsl,vf610-sai",
|
||||
"fsl,imx6sx-sai" or "fsl,imx6ul-sai"
|
||||
"fsl,imx6sx-sai", "fsl,imx6ul-sai",
|
||||
"fsl,imx7ulp-sai", "fsl,imx8mq-sai" or
|
||||
"fsl,imx8qm-sai".
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
* Allwinner A64 Codec Analog Controls
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun50i-a64-codec-analog"
|
||||
- reg: must contain the registers location and length
|
||||
- cpvdd-supply: Regulator supply for the headphone amplifier
|
||||
|
||||
Example:
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
cpvdd-supply = <®_eldo1>;
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
Allwinner SUN8I audio codec
|
||||
------------------------------------
|
||||
|
||||
On Sun8i-A33 SoCs, the audio is separated in different parts:
|
||||
- A DAI driver. It uses the "sun4i-i2s" driver which is
|
||||
documented here:
|
||||
Documentation/devicetree/bindings/sound/sun4i-i2s.txt
|
||||
- An analog part of the codec which is handled as PRCM registers.
|
||||
See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
|
||||
- An digital part of the codec which is documented in this current
|
||||
binding documentation.
|
||||
- And finally, an audio card which links all the above components.
|
||||
The simple-audio card will be used.
|
||||
See Documentation/devicetree/bindings/sound/simple-card.txt
|
||||
|
||||
This bindings documentation exposes Sun8i codec (digital part).
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "allwinner,sun8i-a33-codec"
|
||||
- reg: must contain the registers location and length
|
||||
- interrupts: must contain the codec interrupt
|
||||
- clocks: a list of phandle + clock-specifer pairs, one for each entry
|
||||
in clock-names.
|
||||
- clock-names: should contain followings:
|
||||
- "bus": the parent APB clock for this controller
|
||||
- "mod": the parent module clock
|
||||
|
||||
Here is an example to add a sound card and the codec binding on sun8i SoCs that
|
||||
are similar to A33 using simple-card:
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "sun8i-a33-audio";
|
||||
simple-audio-card,format = "i2s";
|
||||
simple-audio-card,frame-master = <&link_codec>;
|
||||
simple-audio-card,bitclock-master = <&link_codec>;
|
||||
simple-audio-card,mclk-fs = <512>;
|
||||
simple-audio-card,aux-devs = <&codec_analog>;
|
||||
simple-audio-card,routing =
|
||||
"Left DAC", "Digital Left DAC",
|
||||
"Right DAC", "Digital Right DAC";
|
||||
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&dai>;
|
||||
};
|
||||
|
||||
link_codec: simple-audio-card,codec {
|
||||
sound-dai = <&codec>;
|
||||
};
|
||||
|
||||
soc@1c00000 {
|
||||
[...]
|
||||
|
||||
audio-codec@1c22e00 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a33-codec";
|
||||
reg = <0x01c22e00 0x400>;
|
||||
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
|
||||
clock-names = "bus", "mod";
|
||||
};
|
||||
};
|
||||
|
17
Documentation/devicetree/bindings/sound/uda1334.txt
Normal file
17
Documentation/devicetree/bindings/sound/uda1334.txt
Normal file
@ -0,0 +1,17 @@
|
||||
UDA1334 audio CODEC
|
||||
|
||||
This device uses simple GPIO pins for controlling codec settings.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "nxp,uda1334"
|
||||
- nxp,mute-gpios: a GPIO spec for the MUTE pin.
|
||||
- nxp,deemph-gpios: a GPIO spec for the De-emphasis pin
|
||||
|
||||
Example:
|
||||
|
||||
uda1334: audio-codec {
|
||||
compatible = "nxp,uda1334";
|
||||
nxp,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
|
||||
nxp,deemph-gpios = <&gpio3 3 GPIO_ACTIVE_LOW>;
|
||||
};
|
@ -253,24 +253,6 @@ struct hdac_ext_bus_ops {
|
||||
int (*hdev_detach)(struct hdac_device *hdev);
|
||||
};
|
||||
|
||||
/*
|
||||
* Lowlevel I/O operators
|
||||
*/
|
||||
struct hdac_io_ops {
|
||||
/* mapped register accesses */
|
||||
void (*reg_writel)(u32 value, u32 __iomem *addr);
|
||||
u32 (*reg_readl)(u32 __iomem *addr);
|
||||
void (*reg_writew)(u16 value, u16 __iomem *addr);
|
||||
u16 (*reg_readw)(u16 __iomem *addr);
|
||||
void (*reg_writeb)(u8 value, u8 __iomem *addr);
|
||||
u8 (*reg_readb)(u8 __iomem *addr);
|
||||
/* Allocation ops */
|
||||
int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size,
|
||||
struct snd_dma_buffer *buf);
|
||||
void (*dma_free_pages)(struct hdac_bus *bus,
|
||||
struct snd_dma_buffer *buf);
|
||||
};
|
||||
|
||||
#define HDA_UNSOL_QUEUE_SIZE 64
|
||||
#define HDA_MAX_CODECS 8 /* limit by controller side */
|
||||
|
||||
@ -304,7 +286,6 @@ struct hdac_rb {
|
||||
struct hdac_bus {
|
||||
struct device *dev;
|
||||
const struct hdac_bus_ops *ops;
|
||||
const struct hdac_io_ops *io_ops;
|
||||
const struct hdac_ext_bus_ops *ext_ops;
|
||||
|
||||
/* h/w resources */
|
||||
@ -344,6 +325,7 @@ struct hdac_bus {
|
||||
/* CORB/RIRB and position buffers */
|
||||
struct snd_dma_buffer rb;
|
||||
struct snd_dma_buffer posbuf;
|
||||
int dma_type; /* SNDRV_DMA_TYPE_XXX for CORB/RIRB */
|
||||
|
||||
/* hdac_stream linked list */
|
||||
struct list_head stream_list;
|
||||
@ -384,8 +366,7 @@ struct hdac_bus {
|
||||
};
|
||||
|
||||
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops);
|
||||
const struct hdac_bus_ops *ops);
|
||||
void snd_hdac_bus_exit(struct hdac_bus *bus);
|
||||
int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int cmd, unsigned int *res);
|
||||
@ -429,21 +410,38 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
|
||||
int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_ALIGNED_MMIO
|
||||
unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask);
|
||||
void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
|
||||
unsigned int mask);
|
||||
#define snd_hdac_reg_writeb(v, addr) snd_hdac_aligned_write(v, addr, 0xff)
|
||||
#define snd_hdac_reg_writew(v, addr) snd_hdac_aligned_write(v, addr, 0xffff)
|
||||
#define snd_hdac_reg_readb(addr) snd_hdac_aligned_read(addr, 0xff)
|
||||
#define snd_hdac_reg_readw(addr) snd_hdac_aligned_read(addr, 0xffff)
|
||||
#else /* CONFIG_SND_HDA_ALIGNED_MMIO */
|
||||
#define snd_hdac_reg_writeb(val, addr) writeb(val, addr)
|
||||
#define snd_hdac_reg_writew(val, addr) writew(val, addr)
|
||||
#define snd_hdac_reg_readb(addr) readb(addr)
|
||||
#define snd_hdac_reg_readw(addr) readw(addr)
|
||||
#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
|
||||
#define snd_hdac_reg_writel(val, addr) writel(val, addr)
|
||||
#define snd_hdac_reg_readl(addr) readl(addr)
|
||||
|
||||
/*
|
||||
* macros for easy use
|
||||
*/
|
||||
#define _snd_hdac_chip_writeb(chip, reg, value) \
|
||||
((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg))
|
||||
#define _snd_hdac_chip_readb(chip, reg) \
|
||||
((chip)->io_ops->reg_readb((chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_readb((chip)->remap_addr + (reg))
|
||||
#define _snd_hdac_chip_writew(chip, reg, value) \
|
||||
((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_writew(value, (chip)->remap_addr + (reg))
|
||||
#define _snd_hdac_chip_readw(chip, reg) \
|
||||
((chip)->io_ops->reg_readw((chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_readw((chip)->remap_addr + (reg))
|
||||
#define _snd_hdac_chip_writel(chip, reg, value) \
|
||||
((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_writel(value, (chip)->remap_addr + (reg))
|
||||
#define _snd_hdac_chip_readl(chip, reg) \
|
||||
((chip)->io_ops->reg_readl((chip)->remap_addr + (reg)))
|
||||
snd_hdac_reg_readl((chip)->remap_addr + (reg))
|
||||
|
||||
/* read/write a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_chip_writel(chip, reg, value) \
|
||||
@ -548,24 +546,19 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
|
||||
/*
|
||||
* macros for easy use
|
||||
*/
|
||||
#define _snd_hdac_stream_write(type, dev, reg, value) \
|
||||
((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg)))
|
||||
#define _snd_hdac_stream_read(type, dev, reg) \
|
||||
((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg)))
|
||||
|
||||
/* read/write a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_stream_writel(dev, reg, value) \
|
||||
_snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value)
|
||||
snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_writew(dev, reg, value) \
|
||||
_snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value)
|
||||
snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_writeb(dev, reg, value) \
|
||||
_snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value)
|
||||
snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_readl(dev, reg) \
|
||||
_snd_hdac_stream_read(l, dev, AZX_REG_ ## reg)
|
||||
snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_readw(dev, reg) \
|
||||
_snd_hdac_stream_read(w, dev, AZX_REG_ ## reg)
|
||||
snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_readb(dev, reg) \
|
||||
_snd_hdac_stream_read(b, dev, AZX_REG_ ## reg)
|
||||
snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg)
|
||||
|
||||
/* update a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_stream_updatel(dev, reg, mask, val) \
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops,
|
||||
const struct hdac_ext_bus_ops *ext_ops);
|
||||
|
||||
void snd_hdac_ext_bus_exit(struct hdac_bus *bus);
|
||||
|
@ -47,6 +47,9 @@ struct hdmi_codec_params {
|
||||
int channels;
|
||||
};
|
||||
|
||||
typedef void (*hdmi_codec_plugged_cb)(struct device *dev,
|
||||
bool plugged);
|
||||
|
||||
struct hdmi_codec_pdata;
|
||||
struct hdmi_codec_ops {
|
||||
/*
|
||||
@ -88,6 +91,14 @@ struct hdmi_codec_ops {
|
||||
*/
|
||||
int (*get_dai_id)(struct snd_soc_component *comment,
|
||||
struct device_node *endpoint);
|
||||
|
||||
/*
|
||||
* Hook callback function to handle connector plug event.
|
||||
* Optional
|
||||
*/
|
||||
int (*hook_plugged_cb)(struct device *dev, void *data,
|
||||
hdmi_codec_plugged_cb fn,
|
||||
struct device *codec_dev);
|
||||
};
|
||||
|
||||
/* HDMI codec initalization data */
|
||||
@ -99,6 +110,12 @@ struct hdmi_codec_pdata {
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct snd_soc_component;
|
||||
struct snd_soc_jack;
|
||||
|
||||
int hdmi_codec_set_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack);
|
||||
|
||||
#define HDMI_CODEC_DRV_NAME "hdmi-audio-codec"
|
||||
|
||||
#endif /* __HDMI_CODEC_H__ */
|
||||
|
@ -1,18 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* skl-nhlt.h - Intel HDA Platform NHLT header
|
||||
* intel-nhlt.h - Intel HDA Platform NHLT header
|
||||
*
|
||||
* Copyright (C) 2015 Intel Corp
|
||||
* Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Copyright (c) 2015-2019 Intel Corporation
|
||||
*/
|
||||
#ifndef __SKL_NHLT_H__
|
||||
#define __SKL_NHLT_H__
|
||||
|
||||
#ifndef __INTEL_NHLT_H__
|
||||
#define __INTEL_NHLT_H__
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
|
||||
|
||||
struct wav_fmt {
|
||||
u16 fmt_tag;
|
||||
u16 channels;
|
||||
@ -97,16 +96,22 @@ struct nhlt_resource_desc {
|
||||
#define MIC_ARRAY_2CH 2
|
||||
#define MIC_ARRAY_4CH 4
|
||||
|
||||
struct nhlt_tdm_config {
|
||||
struct nhlt_device_specific_config {
|
||||
u8 virtual_slot;
|
||||
u8 config_type;
|
||||
} __packed;
|
||||
|
||||
struct nhlt_dmic_array_config {
|
||||
struct nhlt_tdm_config tdm_config;
|
||||
struct nhlt_device_specific_config device_config;
|
||||
u8 array_type;
|
||||
} __packed;
|
||||
|
||||
struct nhlt_vendor_dmic_array_config {
|
||||
struct nhlt_dmic_array_config dmic_config;
|
||||
u8 nb_mics;
|
||||
/* TODO add vendor mic config */
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
NHLT_MIC_ARRAY_2CH_SMALL = 0xa,
|
||||
NHLT_MIC_ARRAY_2CH_BIG = 0xb,
|
||||
@ -116,4 +121,30 @@ enum {
|
||||
NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf,
|
||||
};
|
||||
|
||||
struct nhlt_acpi_table *intel_nhlt_init(struct device *dev);
|
||||
|
||||
void intel_nhlt_free(struct nhlt_acpi_table *addr);
|
||||
|
||||
int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt);
|
||||
|
||||
#else
|
||||
|
||||
struct nhlt_acpi_table;
|
||||
|
||||
static inline struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void intel_nhlt_free(struct nhlt_acpi_table *addr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int intel_nhlt_get_dmic_geo(struct device *dev,
|
||||
struct nhlt_acpi_table *nhlt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -117,6 +117,8 @@ struct snd_pcm_ops {
|
||||
#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
|
||||
#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
|
||||
#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
|
||||
#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */
|
||||
#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */
|
||||
|
||||
#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
|
||||
#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
|
||||
@ -129,6 +131,9 @@ struct snd_pcm_ops {
|
||||
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
|
||||
#define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\
|
||||
SNDRV_PCM_RATE_352800|\
|
||||
SNDRV_PCM_RATE_384000)
|
||||
#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
|
||||
#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
|
||||
#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
|
||||
|
@ -25,6 +25,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[];
|
||||
|
||||
/*
|
||||
* generic table used for HDA codec-based platforms, possibly with
|
||||
|
387
include/sound/soc-component.h
Normal file
387
include/sound/soc-component.h
Normal file
@ -0,0 +1,387 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* soc-component.h
|
||||
*
|
||||
* Copyright (c) 2019 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __SOC_COMPONENT_H
|
||||
#define __SOC_COMPONENT_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
/*
|
||||
* Component probe and remove ordering levels for components with runtime
|
||||
* dependencies.
|
||||
*/
|
||||
#define SND_SOC_COMP_ORDER_FIRST -2
|
||||
#define SND_SOC_COMP_ORDER_EARLY -1
|
||||
#define SND_SOC_COMP_ORDER_NORMAL 0
|
||||
#define SND_SOC_COMP_ORDER_LATE 1
|
||||
#define SND_SOC_COMP_ORDER_LAST 2
|
||||
|
||||
#define for_each_comp_order(order) \
|
||||
for (order = SND_SOC_COMP_ORDER_FIRST; \
|
||||
order <= SND_SOC_COMP_ORDER_LAST; \
|
||||
order++)
|
||||
|
||||
/* component interface */
|
||||
struct snd_soc_component_driver {
|
||||
const char *name;
|
||||
|
||||
/* Default control and setup, added after probe() is run */
|
||||
const struct snd_kcontrol_new *controls;
|
||||
unsigned int num_controls;
|
||||
const struct snd_soc_dapm_widget *dapm_widgets;
|
||||
unsigned int num_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *dapm_routes;
|
||||
unsigned int num_dapm_routes;
|
||||
|
||||
int (*probe)(struct snd_soc_component *component);
|
||||
void (*remove)(struct snd_soc_component *component);
|
||||
int (*suspend)(struct snd_soc_component *component);
|
||||
int (*resume)(struct snd_soc_component *component);
|
||||
|
||||
unsigned int (*read)(struct snd_soc_component *component,
|
||||
unsigned int reg);
|
||||
int (*write)(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int val);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd);
|
||||
void (*pcm_free)(struct snd_pcm *pcm);
|
||||
|
||||
/* component wide operations */
|
||||
int (*set_sysclk)(struct snd_soc_component *component,
|
||||
int clk_id, int source, unsigned int freq, int dir);
|
||||
int (*set_pll)(struct snd_soc_component *component, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_jack)(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data);
|
||||
|
||||
/* DT */
|
||||
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name);
|
||||
int (*of_xlate_dai_id)(struct snd_soc_component *comment,
|
||||
struct device_node *endpoint);
|
||||
void (*seq_notifier)(struct snd_soc_component *component,
|
||||
enum snd_soc_dapm_type type, int subseq);
|
||||
int (*stream_event)(struct snd_soc_component *component, int event);
|
||||
int (*set_bias_level)(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
const struct snd_pcm_ops *ops;
|
||||
const struct snd_compr_ops *compr_ops;
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
|
||||
/*
|
||||
* signal if the module handling the component should not be removed
|
||||
* if a pcm is open. Setting this would prevent the module
|
||||
* refcount being incremented in probe() but allow it be incremented
|
||||
* when a pcm is opened and decremented when it is closed.
|
||||
*/
|
||||
unsigned int module_get_upon_open:1;
|
||||
|
||||
/* bits */
|
||||
unsigned int idle_bias_on:1;
|
||||
unsigned int suspend_bias_off:1;
|
||||
unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
|
||||
unsigned int endianness:1;
|
||||
unsigned int non_legacy_dai_naming:1;
|
||||
|
||||
/* this component uses topology and ignore machine driver FEs */
|
||||
const char *ignore_machine;
|
||||
const char *topology_name_prefix;
|
||||
int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params);
|
||||
bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
|
||||
int be_pcm_base; /* base device ID for all BE PCMs */
|
||||
};
|
||||
|
||||
struct snd_soc_component {
|
||||
const char *name;
|
||||
int id;
|
||||
const char *name_prefix;
|
||||
struct device *dev;
|
||||
struct snd_soc_card *card;
|
||||
|
||||
unsigned int active;
|
||||
|
||||
unsigned int suspended:1; /* is in suspend PM state */
|
||||
|
||||
struct list_head list;
|
||||
struct list_head card_aux_list; /* for auxiliary bound components */
|
||||
struct list_head card_list;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
|
||||
struct list_head dai_list;
|
||||
int num_dai;
|
||||
|
||||
struct regmap *regmap;
|
||||
int val_bytes;
|
||||
|
||||
struct mutex io_mutex;
|
||||
|
||||
/* attached dynamic objects */
|
||||
struct list_head dobj_list;
|
||||
|
||||
/*
|
||||
* DO NOT use any of the fields below in drivers, they are temporary and
|
||||
* are going to be removed again soon. If you use them in driver code
|
||||
* the driver will be marked as BROKEN when these fields are removed.
|
||||
*/
|
||||
|
||||
/* Don't use these, use snd_soc_component_get_dapm() */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
|
||||
/* machine specific init */
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_root;
|
||||
const char *debugfs_prefix;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define for_each_component_dais(component, dai)\
|
||||
list_for_each_entry(dai, &(component)->dai_list, list)
|
||||
#define for_each_component_dais_safe(component, dai, _dai)\
|
||||
list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_to_component() - Casts a DAPM context to the component it is
|
||||
* embedded in
|
||||
* @dapm: The DAPM context to cast to the component
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a component (e.g. in a component driver). Otherwise the behavior is
|
||||
* undefined.
|
||||
*/
|
||||
static inline struct snd_soc_component *snd_soc_dapm_to_component(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
return container_of(dapm, struct snd_soc_component, dapm);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_get_dapm() - Returns the DAPM context associated with a
|
||||
* component
|
||||
* @component: The component for which to get the DAPM context
|
||||
*/
|
||||
static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return &component->dapm;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to initialize the DAPM bias level
|
||||
* @level: The DAPM level to initialize to
|
||||
*
|
||||
* Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level()
|
||||
*/
|
||||
static inline void
|
||||
snd_soc_component_init_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
snd_soc_dapm_init_bias_level(
|
||||
snd_soc_component_get_dapm(component), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to get the DAPM bias level
|
||||
*
|
||||
* Returns: The current DAPM bias level of the COMPONENT.
|
||||
*/
|
||||
static inline enum snd_soc_bias_level
|
||||
snd_soc_component_get_bias_level(struct snd_soc_component *component)
|
||||
{
|
||||
return snd_soc_dapm_get_bias_level(
|
||||
snd_soc_component_get_dapm(component));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to set the level
|
||||
* @level: The level to set to
|
||||
*
|
||||
* Forces the COMPONENT bias level to a specific state. See
|
||||
* snd_soc_dapm_force_bias_level().
|
||||
*/
|
||||
static inline int
|
||||
snd_soc_component_force_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
return snd_soc_dapm_force_bias_level(
|
||||
snd_soc_component_get_dapm(component),
|
||||
level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_kcontrol_component() - Returns the component associated to a
|
||||
* kcontrol
|
||||
* @kcontrol: The kcontrol
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined
|
||||
*/
|
||||
static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component(
|
||||
struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_cache_sync() - Sync the register cache with the hardware
|
||||
* @component: COMPONENT to sync
|
||||
*
|
||||
* Note: This function will call regcache_sync()
|
||||
*/
|
||||
static inline int snd_soc_component_cache_sync(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return regcache_sync(component->regmap);
|
||||
}
|
||||
|
||||
/* component IO */
|
||||
int snd_soc_component_read(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int *val);
|
||||
unsigned int snd_soc_component_read32(struct snd_soc_component *component,
|
||||
unsigned int reg);
|
||||
int snd_soc_component_write(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int val);
|
||||
int snd_soc_component_update_bits(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val);
|
||||
int snd_soc_component_update_bits_async(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val);
|
||||
void snd_soc_component_async_complete(struct snd_soc_component *component);
|
||||
int snd_soc_component_test_bits(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int value);
|
||||
|
||||
/* component wide operations */
|
||||
int snd_soc_component_set_sysclk(struct snd_soc_component *component,
|
||||
int clk_id, int source,
|
||||
unsigned int freq, int dir);
|
||||
int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
|
||||
int source, unsigned int freq_in,
|
||||
unsigned int freq_out);
|
||||
int snd_soc_component_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data);
|
||||
|
||||
void snd_soc_component_seq_notifier(struct snd_soc_component *component,
|
||||
enum snd_soc_dapm_type type, int subseq);
|
||||
int snd_soc_component_stream_event(struct snd_soc_component *component,
|
||||
int event);
|
||||
int snd_soc_component_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
#ifdef CONFIG_REGMAP
|
||||
void snd_soc_component_init_regmap(struct snd_soc_component *component,
|
||||
struct regmap *regmap);
|
||||
void snd_soc_component_exit_regmap(struct snd_soc_component *component);
|
||||
#endif
|
||||
|
||||
#define snd_soc_component_module_get_when_probe(component)\
|
||||
snd_soc_component_module_get(component, 0)
|
||||
#define snd_soc_component_module_get_when_open(component) \
|
||||
snd_soc_component_module_get(component, 1)
|
||||
int snd_soc_component_module_get(struct snd_soc_component *component,
|
||||
int upon_open);
|
||||
#define snd_soc_component_module_put_when_remove(component) \
|
||||
snd_soc_component_module_put(component, 0)
|
||||
#define snd_soc_component_module_put_when_close(component) \
|
||||
snd_soc_component_module_put(component, 1)
|
||||
void snd_soc_component_module_put(struct snd_soc_component *component,
|
||||
int upon_open);
|
||||
|
||||
static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c,
|
||||
void *data)
|
||||
{
|
||||
dev_set_drvdata(c->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c)
|
||||
{
|
||||
return dev_get_drvdata(c->dev);
|
||||
}
|
||||
|
||||
static inline bool snd_soc_component_is_active(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return component->active != 0;
|
||||
}
|
||||
|
||||
/* component pin */
|
||||
int snd_soc_component_enable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_disable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_nc_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_get_pin_status(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_force_enable_pin_unlocked(
|
||||
struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
|
||||
/* component driver ops */
|
||||
int snd_soc_component_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_component_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_component_prepare(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_component_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int snd_soc_component_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_component_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
int cmd);
|
||||
void snd_soc_component_suspend(struct snd_soc_component *component);
|
||||
void snd_soc_component_resume(struct snd_soc_component *component);
|
||||
int snd_soc_component_is_suspended(struct snd_soc_component *component);
|
||||
int snd_soc_component_probe(struct snd_soc_component *component);
|
||||
void snd_soc_component_remove(struct snd_soc_component *component);
|
||||
int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component,
|
||||
struct device_node *ep);
|
||||
int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name);
|
||||
|
||||
int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream);
|
||||
int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
|
||||
unsigned int cmd, void *arg);
|
||||
int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long pos,
|
||||
void __user *buf, unsigned long bytes);
|
||||
struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream,
|
||||
unsigned long offset);
|
||||
int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma);
|
||||
int snd_soc_pcm_component_new(struct snd_pcm *pcm);
|
||||
void snd_soc_pcm_component_free(struct snd_pcm *pcm);
|
||||
|
||||
#endif /* __SOC_COMPONENT_H */
|
@ -145,6 +145,31 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
|
||||
|
||||
int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
|
||||
|
||||
int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_dai_prepare(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
int snd_soc_dai_trigger(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream, int cmd);
|
||||
int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream, int cmd);
|
||||
snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
|
||||
void snd_soc_dai_resume(struct snd_soc_dai *dai);
|
||||
int snd_soc_dai_probe(struct snd_soc_dai *dai);
|
||||
int snd_soc_dai_remove(struct snd_soc_dai *dai);
|
||||
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
||||
struct snd_soc_pcm_runtime *rtd, int num);
|
||||
bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream);
|
||||
|
||||
struct snd_soc_dai_ops {
|
||||
/*
|
||||
* DAI clocking configuration, all optional.
|
||||
@ -268,8 +293,6 @@ struct snd_soc_dai_driver {
|
||||
/* Optional Callback used at pcm creation*/
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *dai);
|
||||
/* DAI is also used for the control bus */
|
||||
bool bus_control;
|
||||
|
||||
/* ops */
|
||||
const struct snd_soc_dai_ops *ops;
|
||||
@ -281,6 +304,7 @@ struct snd_soc_dai_driver {
|
||||
unsigned int symmetric_rates:1;
|
||||
unsigned int symmetric_channels:1;
|
||||
unsigned int symmetric_samplebits:1;
|
||||
unsigned int bus_control:1; /* DAI is also used for the control bus */
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
|
@ -353,6 +353,8 @@ struct device;
|
||||
#define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
|
||||
#define SND_SOC_DAPM_PRE_POST_PMD \
|
||||
(SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
|
||||
#define SND_SOC_DAPM_PRE_POST_PMU \
|
||||
(SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
|
||||
|
||||
/* convenience event type detection */
|
||||
#define SND_SOC_DAPM_EVENT_ON(e) \
|
||||
@ -417,6 +419,9 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
|
||||
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
|
||||
void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_soc_card *card,
|
||||
struct snd_soc_component *component);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
|
||||
@ -662,8 +667,6 @@ struct snd_soc_dapm_context {
|
||||
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
|
||||
/* Go to BIAS_OFF in suspend if the DAPM context is idle */
|
||||
unsigned int suspend_bias_off:1;
|
||||
void (*seq_notifier)(struct snd_soc_dapm_context *,
|
||||
enum snd_soc_dapm_type, int);
|
||||
|
||||
struct device *dev; /* from parent - for debug */
|
||||
struct snd_soc_component *component; /* parent component */
|
||||
@ -673,10 +676,6 @@ struct snd_soc_dapm_context {
|
||||
enum snd_soc_bias_level target_bias_level;
|
||||
struct list_head list;
|
||||
|
||||
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
|
||||
int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
struct snd_soc_dapm_wcache path_sink_cache;
|
||||
struct snd_soc_dapm_wcache path_source_cache;
|
||||
|
||||
|
@ -142,9 +142,16 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
|
||||
|
||||
/* internal use only */
|
||||
int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
|
||||
void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
|
||||
int soc_dpcm_runtime_update(struct snd_soc_card *);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
|
||||
#else
|
||||
static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
|
||||
int stream, struct snd_soc_dapm_widget_list **list_);
|
||||
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
|
||||
|
@ -362,21 +362,6 @@
|
||||
#define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
|
||||
const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
|
||||
|
||||
/*
|
||||
* Component probe and remove ordering levels for components with runtime
|
||||
* dependencies.
|
||||
*/
|
||||
#define SND_SOC_COMP_ORDER_FIRST -2
|
||||
#define SND_SOC_COMP_ORDER_EARLY -1
|
||||
#define SND_SOC_COMP_ORDER_NORMAL 0
|
||||
#define SND_SOC_COMP_ORDER_LATE 1
|
||||
#define SND_SOC_COMP_ORDER_LAST 2
|
||||
|
||||
#define for_each_comp_order(order) \
|
||||
for (order = SND_SOC_COMP_ORDER_FIRST; \
|
||||
order <= SND_SOC_COMP_ORDER_LAST; \
|
||||
order++)
|
||||
|
||||
/*
|
||||
* Bias levels
|
||||
*
|
||||
@ -505,10 +490,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
|
||||
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
||||
const struct snd_pcm_hardware *hw);
|
||||
|
||||
int soc_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
/* Jack reporting */
|
||||
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
|
||||
struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
|
||||
@ -751,132 +732,6 @@ struct snd_soc_compr_ops {
|
||||
int (*trigger)(struct snd_compr_stream *);
|
||||
};
|
||||
|
||||
/* component interface */
|
||||
struct snd_soc_component_driver {
|
||||
const char *name;
|
||||
|
||||
/* Default control and setup, added after probe() is run */
|
||||
const struct snd_kcontrol_new *controls;
|
||||
unsigned int num_controls;
|
||||
const struct snd_soc_dapm_widget *dapm_widgets;
|
||||
unsigned int num_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *dapm_routes;
|
||||
unsigned int num_dapm_routes;
|
||||
|
||||
int (*probe)(struct snd_soc_component *);
|
||||
void (*remove)(struct snd_soc_component *);
|
||||
int (*suspend)(struct snd_soc_component *);
|
||||
int (*resume)(struct snd_soc_component *);
|
||||
|
||||
unsigned int (*read)(struct snd_soc_component *, unsigned int);
|
||||
int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* component wide operations */
|
||||
int (*set_sysclk)(struct snd_soc_component *component,
|
||||
int clk_id, int source, unsigned int freq, int dir);
|
||||
int (*set_pll)(struct snd_soc_component *component, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_jack)(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data);
|
||||
|
||||
/* DT */
|
||||
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name);
|
||||
int (*of_xlate_dai_id)(struct snd_soc_component *comment,
|
||||
struct device_node *endpoint);
|
||||
void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
|
||||
int subseq);
|
||||
int (*stream_event)(struct snd_soc_component *, int event);
|
||||
int (*set_bias_level)(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
const struct snd_pcm_ops *ops;
|
||||
const struct snd_compr_ops *compr_ops;
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
|
||||
/*
|
||||
* signal if the module handling the component should not be removed
|
||||
* if a pcm is open. Setting this would prevent the module
|
||||
* refcount being incremented in probe() but allow it be incremented
|
||||
* when a pcm is opened and decremented when it is closed.
|
||||
*/
|
||||
unsigned int module_get_upon_open:1;
|
||||
|
||||
/* bits */
|
||||
unsigned int idle_bias_on:1;
|
||||
unsigned int suspend_bias_off:1;
|
||||
unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
|
||||
unsigned int endianness:1;
|
||||
unsigned int non_legacy_dai_naming:1;
|
||||
|
||||
/* this component uses topology and ignore machine driver FEs */
|
||||
const char *ignore_machine;
|
||||
const char *topology_name_prefix;
|
||||
int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params);
|
||||
bool use_dai_pcm_id; /* use the DAI link PCM ID as PCM device number */
|
||||
int be_pcm_base; /* base device ID for all BE PCMs */
|
||||
};
|
||||
|
||||
struct snd_soc_component {
|
||||
const char *name;
|
||||
int id;
|
||||
const char *name_prefix;
|
||||
struct device *dev;
|
||||
struct snd_soc_card *card;
|
||||
|
||||
unsigned int active;
|
||||
|
||||
unsigned int suspended:1; /* is in suspend PM state */
|
||||
|
||||
struct list_head list;
|
||||
struct list_head card_aux_list; /* for auxiliary bound components */
|
||||
struct list_head card_list;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
|
||||
struct list_head dai_list;
|
||||
int num_dai;
|
||||
|
||||
struct regmap *regmap;
|
||||
int val_bytes;
|
||||
|
||||
struct mutex io_mutex;
|
||||
|
||||
/* attached dynamic objects */
|
||||
struct list_head dobj_list;
|
||||
|
||||
/*
|
||||
* DO NOT use any of the fields below in drivers, they are temporary and
|
||||
* are going to be removed again soon. If you use them in driver code the
|
||||
* driver will be marked as BROKEN when these fields are removed.
|
||||
*/
|
||||
|
||||
/* Don't use these, use snd_soc_component_get_dapm() */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
|
||||
/* machine specific init */
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_root;
|
||||
const char *debugfs_prefix;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define for_each_component_dais(component, dai)\
|
||||
list_for_each_entry(dai, &(component)->dai_list, list)
|
||||
#define for_each_component_dais_safe(component, dai, _dai)\
|
||||
list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
|
||||
|
||||
struct snd_soc_rtdcom_list {
|
||||
struct snd_soc_component *component;
|
||||
struct list_head list; /* rtd::component_list */
|
||||
@ -1086,6 +941,7 @@ struct snd_soc_dai_link {
|
||||
#define COMP_CPU(_dai) { .dai_name = _dai, }
|
||||
#define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, }
|
||||
#define COMP_PLATFORM(_name) { .name = _name }
|
||||
#define COMP_AUX(_name) { .name = _name }
|
||||
#define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", }
|
||||
|
||||
extern struct snd_soc_dai_link_component null_dailink_component[0];
|
||||
@ -1107,14 +963,11 @@ struct snd_soc_codec_conf {
|
||||
};
|
||||
|
||||
struct snd_soc_aux_dev {
|
||||
const char *name; /* Codec name */
|
||||
|
||||
/*
|
||||
* specify multi-codec either by device name, or by
|
||||
* DT/OF node, but not both.
|
||||
*/
|
||||
const char *codec_name;
|
||||
struct device_node *codec_of_node;
|
||||
struct snd_soc_dai_link_component dlc;
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
@ -1135,6 +988,10 @@ struct snd_soc_card {
|
||||
struct mutex mutex;
|
||||
struct mutex dapm_mutex;
|
||||
|
||||
/* Mutex for PCM operations */
|
||||
struct mutex pcm_mutex;
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
|
||||
spinlock_t dpcm_lock;
|
||||
|
||||
bool instantiated;
|
||||
@ -1203,8 +1060,6 @@ struct snd_soc_card {
|
||||
int num_of_dapm_routes;
|
||||
bool fully_routed;
|
||||
|
||||
struct work_struct deferred_resume_work;
|
||||
|
||||
/* lists of probed devices belonging to this card */
|
||||
struct list_head component_dev_list;
|
||||
struct list_head list;
|
||||
@ -1224,7 +1079,9 @@ struct snd_soc_card {
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_card_root;
|
||||
struct dentry *debugfs_pop_time;
|
||||
#endif
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct work_struct deferred_resume_work;
|
||||
#endif
|
||||
u32 pop_time;
|
||||
|
||||
@ -1234,6 +1091,10 @@ struct snd_soc_card {
|
||||
for ((i) = 0; \
|
||||
((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \
|
||||
(i)++)
|
||||
#define for_each_card_pre_auxs(card, i, aux) \
|
||||
for ((i) = 0; \
|
||||
((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \
|
||||
(i)++)
|
||||
|
||||
#define for_each_card_links(card, link) \
|
||||
list_for_each_entry(link, &(card)->dai_link_list, list)
|
||||
@ -1245,6 +1106,12 @@ struct snd_soc_card {
|
||||
#define for_each_card_rtds_safe(card, rtd, _rtd) \
|
||||
list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list)
|
||||
|
||||
#define for_each_card_auxs(card, component) \
|
||||
list_for_each_entry(component, &card->aux_comp_list, card_aux_list)
|
||||
#define for_each_card_auxs_safe(card, component, _comp) \
|
||||
list_for_each_entry_safe(component, _comp, \
|
||||
&card->aux_comp_list, card_aux_list)
|
||||
|
||||
#define for_each_card_components(card, component) \
|
||||
list_for_each_entry(component, &(card)->component_dev_list, card_list)
|
||||
|
||||
@ -1253,8 +1120,6 @@ struct snd_soc_pcm_runtime {
|
||||
struct device *dev;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
struct mutex pcm_mutex;
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
struct snd_pcm_ops ops;
|
||||
|
||||
unsigned int params_select; /* currently selected param for dai link */
|
||||
@ -1342,134 +1207,6 @@ struct soc_enum {
|
||||
struct snd_soc_dobj dobj;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_to_component() - Casts a DAPM context to the component it is
|
||||
* embedded in
|
||||
* @dapm: The DAPM context to cast to the component
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a component (e.g. in a component driver). Otherwise the behavior is
|
||||
* undefined.
|
||||
*/
|
||||
static inline struct snd_soc_component *snd_soc_dapm_to_component(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
return container_of(dapm, struct snd_soc_component, dapm);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_get_dapm() - Returns the DAPM context associated with a
|
||||
* component
|
||||
* @component: The component for which to get the DAPM context
|
||||
*/
|
||||
static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return &component->dapm;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to initialize the DAPM bias level
|
||||
* @level: The DAPM level to initialize to
|
||||
*
|
||||
* Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level().
|
||||
*/
|
||||
static inline void
|
||||
snd_soc_component_init_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
snd_soc_dapm_init_bias_level(
|
||||
snd_soc_component_get_dapm(component), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to get the DAPM bias level
|
||||
*
|
||||
* Returns: The current DAPM bias level of the COMPONENT.
|
||||
*/
|
||||
static inline enum snd_soc_bias_level
|
||||
snd_soc_component_get_bias_level(struct snd_soc_component *component)
|
||||
{
|
||||
return snd_soc_dapm_get_bias_level(
|
||||
snd_soc_component_get_dapm(component));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level
|
||||
* @component: The COMPONENT for which to set the level
|
||||
* @level: The level to set to
|
||||
*
|
||||
* Forces the COMPONENT bias level to a specific state. See
|
||||
* snd_soc_dapm_force_bias_level().
|
||||
*/
|
||||
static inline int
|
||||
snd_soc_component_force_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
return snd_soc_dapm_force_bias_level(
|
||||
snd_soc_component_get_dapm(component),
|
||||
level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_kcontrol_component() - Returns the component associated to a kcontrol
|
||||
* @kcontrol: The kcontrol
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined.
|
||||
*/
|
||||
static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component(
|
||||
struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_component_cache_sync() - Sync the register cache with the hardware
|
||||
* @component: COMPONENT to sync
|
||||
*
|
||||
* Note: This function will call regcache_sync()
|
||||
*/
|
||||
static inline int snd_soc_component_cache_sync(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return regcache_sync(component->regmap);
|
||||
}
|
||||
|
||||
/* component IO */
|
||||
int snd_soc_component_read(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int *val);
|
||||
unsigned int snd_soc_component_read32(struct snd_soc_component *component,
|
||||
unsigned int reg);
|
||||
int snd_soc_component_write(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int val);
|
||||
int snd_soc_component_update_bits(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask, unsigned int val);
|
||||
int snd_soc_component_update_bits_async(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask, unsigned int val);
|
||||
void snd_soc_component_async_complete(struct snd_soc_component *component);
|
||||
int snd_soc_component_test_bits(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask, unsigned int value);
|
||||
|
||||
/* component wide operations */
|
||||
int snd_soc_component_set_sysclk(struct snd_soc_component *component,
|
||||
int clk_id, int source, unsigned int freq, int dir);
|
||||
int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id,
|
||||
int source, unsigned int freq_in,
|
||||
unsigned int freq_out);
|
||||
int snd_soc_component_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data);
|
||||
|
||||
#ifdef CONFIG_REGMAP
|
||||
|
||||
void snd_soc_component_init_regmap(struct snd_soc_component *component,
|
||||
struct regmap *regmap);
|
||||
void snd_soc_component_exit_regmap(struct snd_soc_component *component);
|
||||
|
||||
#endif
|
||||
|
||||
/* device driver data */
|
||||
|
||||
static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
|
||||
@ -1483,27 +1220,6 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card)
|
||||
return card->drvdata;
|
||||
}
|
||||
|
||||
static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c,
|
||||
void *data)
|
||||
{
|
||||
dev_set_drvdata(c->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c)
|
||||
{
|
||||
return dev_get_drvdata(c->dev);
|
||||
}
|
||||
|
||||
static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
|
||||
{
|
||||
INIT_LIST_HEAD(&card->widgets);
|
||||
INIT_LIST_HEAD(&card->paths);
|
||||
INIT_LIST_HEAD(&card->dapm_list);
|
||||
INIT_LIST_HEAD(&card->aux_comp_list);
|
||||
INIT_LIST_HEAD(&card->component_dev_list);
|
||||
INIT_LIST_HEAD(&card->list);
|
||||
}
|
||||
|
||||
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
|
||||
{
|
||||
if (mc->reg == mc->rreg && mc->shift == mc->rshift)
|
||||
@ -1540,12 +1256,6 @@ static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e,
|
||||
return e->values[item];
|
||||
}
|
||||
|
||||
static inline bool snd_soc_component_is_active(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return component->active != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_kcontrol_component() - Returns the component that registered the
|
||||
* control
|
||||
@ -1681,24 +1391,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
|
||||
mutex_unlock(&dapm->card->dapm_mutex);
|
||||
}
|
||||
|
||||
int snd_soc_component_enable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_disable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_nc_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_get_pin_status(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
int snd_soc_component_force_enable_pin_unlocked(
|
||||
struct snd_soc_component *component,
|
||||
const char *pin);
|
||||
#include <sound/soc-component.h>
|
||||
|
||||
#endif
|
||||
|
@ -76,6 +76,9 @@ struct sof_ipc_dai_ssp_params {
|
||||
uint16_t tdm_per_slot_padding_flag;
|
||||
uint32_t clks_control;
|
||||
uint32_t quirks;
|
||||
uint32_t bclk_delay; /* guaranteed time (ms) for which BCLK
|
||||
* will be driven, before sending data
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */
|
||||
@ -176,4 +179,13 @@ struct sof_ipc_dai_dmic_params {
|
||||
struct sof_ipc_dai_dmic_pdm_ctrl pdm[0];
|
||||
} __packed;
|
||||
|
||||
/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */
|
||||
struct sof_ipc_dai_alh_params {
|
||||
struct sof_ipc_hdr hdr;
|
||||
uint32_t stream_id;
|
||||
|
||||
/* reserved for future use */
|
||||
uint32_t reserved[15];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@ -49,7 +49,9 @@ enum sof_ipc_dai_type {
|
||||
SOF_DAI_INTEL_SSP, /**< Intel SSP */
|
||||
SOF_DAI_INTEL_DMIC, /**< Intel DMIC */
|
||||
SOF_DAI_INTEL_HDA, /**< Intel HD/A */
|
||||
SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */
|
||||
SOF_DAI_INTEL_ALH, /**< Intel ALH */
|
||||
SOF_DAI_IMX_SAI, /**< i.MX SAI */
|
||||
SOF_DAI_IMX_ESAI, /**< i.MX ESAI */
|
||||
};
|
||||
|
||||
/* general purpose DAI configuration */
|
||||
@ -70,6 +72,7 @@ struct sof_ipc_dai_config {
|
||||
struct sof_ipc_dai_ssp_params ssp;
|
||||
struct sof_ipc_dai_dmic_params dmic;
|
||||
struct sof_ipc_dai_hda_params hda;
|
||||
struct sof_ipc_dai_alh_params alh;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
/* SOF ABI version major, minor and patch numbers */
|
||||
#define SOF_ABI_MAJOR 3
|
||||
#define SOF_ABI_MINOR 8
|
||||
#define SOF_ABI_MINOR 10
|
||||
#define SOF_ABI_PATCH 0
|
||||
|
||||
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
|
||||
|
@ -75,6 +75,7 @@
|
||||
#define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503
|
||||
#define SOF_TKN_INTEL_SSP_QUIRKS 504
|
||||
#define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505
|
||||
#define SOF_TKN_INTEL_SSP_BCLK_DELAY 506
|
||||
|
||||
/* DMIC */
|
||||
#define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600
|
||||
@ -105,4 +106,12 @@
|
||||
/* for backward compatibility */
|
||||
#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE
|
||||
|
||||
/* SAI */
|
||||
#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000
|
||||
/* TODO: Add SAI tokens */
|
||||
|
||||
/* ESAI */
|
||||
#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100
|
||||
/* TODO: Add ESAI tokens */
|
||||
|
||||
#endif
|
||||
|
@ -2170,7 +2170,7 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
|
||||
|
||||
static const unsigned int rates[] = {
|
||||
5512, 8000, 11025, 16000, 22050, 32000, 44100,
|
||||
48000, 64000, 88200, 96000, 176400, 192000
|
||||
48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000
|
||||
};
|
||||
|
||||
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
|
||||
|
@ -6,6 +6,9 @@ config SND_HDA_CORE
|
||||
config SND_HDA_DSP_LOADER
|
||||
bool
|
||||
|
||||
config SND_HDA_ALIGNED_MMIO
|
||||
bool
|
||||
|
||||
config SND_HDA_COMPONENT
|
||||
bool
|
||||
|
||||
@ -29,3 +32,8 @@ config SND_HDA_PREALLOC_SIZE
|
||||
|
||||
Note that the pre-allocation size can be changed dynamically
|
||||
via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
|
||||
|
||||
config SND_INTEL_NHLT
|
||||
tristate
|
||||
# this config should be selected only for Intel ACPI platforms.
|
||||
# A fallback is provided so that the code compiles in all cases.
|
@ -13,3 +13,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
|
||||
|
||||
#extended hda
|
||||
obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
|
||||
|
||||
snd-intel-nhlt-objs := intel-nhlt.o
|
||||
obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o
|
||||
|
@ -17,80 +17,22 @@
|
||||
MODULE_DESCRIPTION("HDA extended core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static void hdac_ext_writel(u32 value, u32 __iomem *addr)
|
||||
{
|
||||
writel(value, addr);
|
||||
}
|
||||
|
||||
static u32 hdac_ext_readl(u32 __iomem *addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
static void hdac_ext_writew(u16 value, u16 __iomem *addr)
|
||||
{
|
||||
writew(value, addr);
|
||||
}
|
||||
|
||||
static u16 hdac_ext_readw(u16 __iomem *addr)
|
||||
{
|
||||
return readw(addr);
|
||||
}
|
||||
|
||||
static void hdac_ext_writeb(u8 value, u8 __iomem *addr)
|
||||
{
|
||||
writeb(value, addr);
|
||||
}
|
||||
|
||||
static u8 hdac_ext_readb(u8 __iomem *addr)
|
||||
{
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
static int hdac_ext_dma_alloc_pages(struct hdac_bus *bus, int type,
|
||||
size_t size, struct snd_dma_buffer *buf)
|
||||
{
|
||||
return snd_dma_alloc_pages(type, bus->dev, size, buf);
|
||||
}
|
||||
|
||||
static void hdac_ext_dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
|
||||
{
|
||||
snd_dma_free_pages(buf);
|
||||
}
|
||||
|
||||
static const struct hdac_io_ops hdac_ext_default_io = {
|
||||
.reg_writel = hdac_ext_writel,
|
||||
.reg_readl = hdac_ext_readl,
|
||||
.reg_writew = hdac_ext_writew,
|
||||
.reg_readw = hdac_ext_readw,
|
||||
.reg_writeb = hdac_ext_writeb,
|
||||
.reg_readb = hdac_ext_readb,
|
||||
.dma_alloc_pages = hdac_ext_dma_alloc_pages,
|
||||
.dma_free_pages = hdac_ext_dma_free_pages,
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_bus_init - initialize a HD-audio extended bus
|
||||
* @ebus: the pointer to extended bus object
|
||||
* @dev: device pointer
|
||||
* @ops: bus verb operators
|
||||
* @io_ops: lowlevel I/O operators, can be NULL. If NULL core will use
|
||||
* default ops
|
||||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops,
|
||||
const struct hdac_ext_bus_ops *ext_ops)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* check if io ops are provided, if not load the defaults */
|
||||
if (io_ops == NULL)
|
||||
io_ops = &hdac_ext_default_io;
|
||||
|
||||
ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
|
||||
ret = snd_hdac_bus_init(bus, dev, ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
@ -19,13 +20,11 @@ static const struct hdac_bus_ops default_ops = {
|
||||
* snd_hdac_bus_init - initialize a HD-audio bas bus
|
||||
* @bus: the pointer to bus object
|
||||
* @ops: bus verb operators
|
||||
* @io_ops: lowlevel I/O operators
|
||||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops)
|
||||
const struct hdac_bus_ops *ops)
|
||||
{
|
||||
memset(bus, 0, sizeof(*bus));
|
||||
bus->dev = dev;
|
||||
@ -33,7 +32,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
bus->ops = ops;
|
||||
else
|
||||
bus->ops = &default_ops;
|
||||
bus->io_ops = io_ops;
|
||||
bus->dma_type = SNDRV_DMA_TYPE_DEV;
|
||||
INIT_LIST_HEAD(&bus->stream_list);
|
||||
INIT_LIST_HEAD(&bus->codec_list);
|
||||
INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
|
||||
@ -217,3 +216,33 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus,
|
||||
flush_work(&bus->unsol_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_ALIGNED_MMIO
|
||||
/* Helpers for aligned read/write of mmio space, for Tegra */
|
||||
unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask)
|
||||
{
|
||||
void __iomem *aligned_addr =
|
||||
(void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
unsigned int v;
|
||||
|
||||
v = readl(aligned_addr);
|
||||
return (v >> shift) & mask;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_aligned_read);
|
||||
|
||||
void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
|
||||
unsigned int mask)
|
||||
{
|
||||
void __iomem *aligned_addr =
|
||||
(void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
unsigned int v;
|
||||
|
||||
v = readl(aligned_addr);
|
||||
v &= ~(mask << shift);
|
||||
v |= val << shift;
|
||||
writel(v, aligned_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_aligned_write);
|
||||
#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
|
||||
|
@ -575,12 +575,13 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
|
||||
{
|
||||
struct hdac_stream *s;
|
||||
int num_streams = 0;
|
||||
int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV;
|
||||
int err;
|
||||
|
||||
list_for_each_entry(s, &bus->stream_list, list) {
|
||||
/* allocate memory for the BDL for each stream */
|
||||
err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
|
||||
BDL_SIZE, &s->bdl);
|
||||
err = snd_dma_alloc_pages(dma_type, bus->dev,
|
||||
BDL_SIZE, &s->bdl);
|
||||
num_streams++;
|
||||
if (err < 0)
|
||||
return -ENOMEM;
|
||||
@ -589,16 +590,15 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
|
||||
if (WARN_ON(!num_streams))
|
||||
return -EINVAL;
|
||||
/* allocate memory for the position buffer */
|
||||
err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
|
||||
num_streams * 8, &bus->posbuf);
|
||||
err = snd_dma_alloc_pages(dma_type, bus->dev,
|
||||
num_streams * 8, &bus->posbuf);
|
||||
if (err < 0)
|
||||
return -ENOMEM;
|
||||
list_for_each_entry(s, &bus->stream_list, list)
|
||||
s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
|
||||
|
||||
/* single page (at least 4096 bytes) must suffice for both ringbuffes */
|
||||
return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV,
|
||||
PAGE_SIZE, &bus->rb);
|
||||
return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
|
||||
|
||||
@ -612,12 +612,12 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
|
||||
|
||||
list_for_each_entry(s, &bus->stream_list, list) {
|
||||
if (s->bdl.area)
|
||||
bus->io_ops->dma_free_pages(bus, &s->bdl);
|
||||
snd_dma_free_pages(&s->bdl);
|
||||
}
|
||||
|
||||
if (bus->rb.area)
|
||||
bus->io_ops->dma_free_pages(bus, &bus->rb);
|
||||
snd_dma_free_pages(&bus->rb);
|
||||
if (bus->posbuf.area)
|
||||
bus->io_ops->dma_free_pages(bus, &bus->posbuf);
|
||||
snd_dma_free_pages(&bus->posbuf);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
|
||||
|
@ -680,8 +680,8 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
|
||||
azx_dev->locked = true;
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV_SG,
|
||||
byte_size, bufp);
|
||||
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev,
|
||||
byte_size, bufp);
|
||||
if (err < 0)
|
||||
goto err_alloc;
|
||||
|
||||
@ -707,7 +707,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
|
||||
return azx_dev->stream_tag;
|
||||
|
||||
error:
|
||||
bus->io_ops->dma_free_pages(bus, bufp);
|
||||
snd_dma_free_pages(bufp);
|
||||
err_alloc:
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
azx_dev->locked = false;
|
||||
@ -754,7 +754,7 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
|
||||
azx_dev->period_bytes = 0;
|
||||
azx_dev->format_val = 0;
|
||||
|
||||
bus->io_ops->dma_free_pages(bus, dmab);
|
||||
snd_dma_free_pages(dmab);
|
||||
dmab->area = NULL;
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
|
107
sound/hda/intel-nhlt.c
Normal file
107
sound/hda/intel-nhlt.c
Normal file
@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2015-2019 Intel Corporation
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <sound/intel-nhlt.h>
|
||||
|
||||
#define NHLT_ACPI_HEADER_SIG "NHLT"
|
||||
|
||||
/* Unique identification for getting NHLT blobs */
|
||||
static guid_t osc_guid =
|
||||
GUID_INIT(0xA69F886E, 0x6CEB, 0x4594,
|
||||
0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53);
|
||||
|
||||
struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *obj;
|
||||
struct nhlt_resource_desc *nhlt_ptr;
|
||||
struct nhlt_acpi_table *nhlt_table = NULL;
|
||||
|
||||
handle = ACPI_HANDLE(dev);
|
||||
if (!handle) {
|
||||
dev_err(dev, "Didn't find ACPI_HANDLE\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL);
|
||||
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
dev_dbg(dev, "No NHLT table found\n");
|
||||
ACPI_FREE(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
|
||||
if (nhlt_ptr->length)
|
||||
nhlt_table = (struct nhlt_acpi_table *)
|
||||
memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
|
||||
MEMREMAP_WB);
|
||||
ACPI_FREE(obj);
|
||||
if (nhlt_table &&
|
||||
(strncmp(nhlt_table->header.signature,
|
||||
NHLT_ACPI_HEADER_SIG,
|
||||
strlen(NHLT_ACPI_HEADER_SIG)) != 0)) {
|
||||
memunmap(nhlt_table);
|
||||
dev_err(dev, "NHLT ACPI header signature incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
return nhlt_table;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(intel_nhlt_init);
|
||||
|
||||
void intel_nhlt_free(struct nhlt_acpi_table *nhlt)
|
||||
{
|
||||
memunmap((void *)nhlt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(intel_nhlt_free);
|
||||
|
||||
int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
|
||||
{
|
||||
struct nhlt_endpoint *epnt;
|
||||
struct nhlt_dmic_array_config *cfg;
|
||||
struct nhlt_vendor_dmic_array_config *cfg_vendor;
|
||||
unsigned int dmic_geo = 0;
|
||||
u8 j;
|
||||
|
||||
if (!nhlt)
|
||||
return 0;
|
||||
|
||||
epnt = (struct nhlt_endpoint *)nhlt->desc;
|
||||
|
||||
for (j = 0; j < nhlt->endpoint_count; j++) {
|
||||
if (epnt->linktype == NHLT_LINK_DMIC) {
|
||||
cfg = (struct nhlt_dmic_array_config *)
|
||||
(epnt->config.caps);
|
||||
switch (cfg->array_type) {
|
||||
case NHLT_MIC_ARRAY_2CH_SMALL:
|
||||
case NHLT_MIC_ARRAY_2CH_BIG:
|
||||
dmic_geo = MIC_ARRAY_2CH;
|
||||
break;
|
||||
|
||||
case NHLT_MIC_ARRAY_4CH_1ST_GEOM:
|
||||
case NHLT_MIC_ARRAY_4CH_L_SHAPED:
|
||||
case NHLT_MIC_ARRAY_4CH_2ND_GEOM:
|
||||
dmic_geo = MIC_ARRAY_4CH;
|
||||
break;
|
||||
case NHLT_MIC_ARRAY_VENDOR_DEFINED:
|
||||
cfg_vendor = (struct nhlt_vendor_dmic_array_config *)cfg;
|
||||
dmic_geo = cfg_vendor->nb_mics;
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "undefined DMIC array_type 0x%0x\n",
|
||||
cfg->array_type);
|
||||
}
|
||||
}
|
||||
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
|
||||
}
|
||||
|
||||
return dmic_geo;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel NHLT driver");
|
@ -12,6 +12,7 @@ config SND_HDA_INTEL
|
||||
tristate "HD Audio PCI"
|
||||
depends on SND_PCI
|
||||
select SND_HDA
|
||||
select SND_INTEL_NHLT if ACPI
|
||||
help
|
||||
Say Y here to include support for Intel "High Definition
|
||||
Audio" (Azalia) and its compatible devices.
|
||||
@ -22,10 +23,20 @@ config SND_HDA_INTEL
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-hda-intel.
|
||||
|
||||
config SND_HDA_INTEL_DETECT_DMIC
|
||||
bool "DMIC detection and probe abort"
|
||||
depends on SND_HDA_INTEL
|
||||
help
|
||||
Say Y to detect digital microphones on SKL+ devices. DMICs
|
||||
cannot be handled by the HDaudio legacy driver and are
|
||||
currently only supported by the SOF driver.
|
||||
If unsure say N.
|
||||
|
||||
config SND_HDA_TEGRA
|
||||
tristate "NVIDIA Tegra HD Audio"
|
||||
depends on ARCH_TEGRA
|
||||
select SND_HDA
|
||||
select SND_HDA_ALIGNED_MMIO
|
||||
help
|
||||
Say Y here to support the HDA controller present in NVIDIA
|
||||
Tegra SoCs
|
||||
|
@ -846,7 +846,13 @@ static void snd_hda_codec_dev_release(struct device *dev)
|
||||
snd_hda_sysfs_clear(codec);
|
||||
kfree(codec->modelname);
|
||||
kfree(codec->wcaps);
|
||||
kfree(codec);
|
||||
|
||||
/*
|
||||
* In the case of ASoC HD-audio, hda_codec is device managed.
|
||||
* It will be freed when the ASoC device is removed.
|
||||
*/
|
||||
if (codec->core.type == HDA_DEV_LEGACY)
|
||||
kfree(codec);
|
||||
}
|
||||
|
||||
#define DEV_NAME_LEN 31
|
||||
|
@ -1207,14 +1207,12 @@ void snd_hda_bus_reset(struct hda_bus *bus)
|
||||
}
|
||||
|
||||
/* HD-audio bus initialization */
|
||||
int azx_bus_init(struct azx *chip, const char *model,
|
||||
const struct hdac_io_ops *io_ops)
|
||||
int azx_bus_init(struct azx *chip, const char *model)
|
||||
{
|
||||
struct hda_bus *bus = &chip->bus;
|
||||
int err;
|
||||
|
||||
err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops,
|
||||
io_ops);
|
||||
err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -206,8 +206,7 @@ void azx_stop_chip(struct azx *chip);
|
||||
irqreturn_t azx_interrupt(int irq, void *dev_id);
|
||||
|
||||
/* Codec interface */
|
||||
int azx_bus_init(struct azx *chip, const char *model,
|
||||
const struct hdac_io_ops *io_ops);
|
||||
int azx_bus_init(struct azx *chip, const char *model);
|
||||
int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
|
||||
int azx_codec_configure(struct azx *chip);
|
||||
int azx_init_streams(struct azx *chip);
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_i915.h>
|
||||
#include <sound/intel-nhlt.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <linux/firmware.h>
|
||||
@ -125,6 +126,7 @@ static char *patch[SNDRV_CARDS];
|
||||
static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
|
||||
CONFIG_SND_HDA_INPUT_BEEP_MODE};
|
||||
#endif
|
||||
static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC);
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
||||
@ -159,6 +161,8 @@ module_param_array(beep_mode, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
|
||||
"(0=off, 1=on) (default=1).");
|
||||
#endif
|
||||
module_param(dmic_detect, bool, 0444);
|
||||
MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int param_set_xint(const char *val, const struct kernel_param *kp);
|
||||
@ -1684,7 +1688,6 @@ static int default_bdl_pos_adj(struct azx *chip)
|
||||
/*
|
||||
* constructor
|
||||
*/
|
||||
static const struct hdac_io_ops pci_hda_io_ops;
|
||||
static const struct hda_controller_ops pci_hda_ops;
|
||||
|
||||
static int azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||
@ -1744,13 +1747,17 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||
else
|
||||
chip->bdl_pos_adj = bdl_pos_adj[dev];
|
||||
|
||||
err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
|
||||
err = azx_bus_init(chip, model[dev]);
|
||||
if (err < 0) {
|
||||
kfree(hda);
|
||||
pci_disable_device(pci);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* use the non-cached pages in non-snoop mode */
|
||||
if (!azx_snoop(chip))
|
||||
azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_UC;
|
||||
|
||||
/* Workaround for a communication error on CFL (bko#199007) and CNL */
|
||||
if (IS_CFL(pci) || IS_CNL(pci))
|
||||
azx_bus(chip)->polling_mode = 1;
|
||||
@ -1985,41 +1992,6 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* HDA controller ops.
|
||||
*/
|
||||
|
||||
/* PCI register access. */
|
||||
static void pci_azx_writel(u32 value, u32 __iomem *addr)
|
||||
{
|
||||
writel(value, addr);
|
||||
}
|
||||
|
||||
static u32 pci_azx_readl(u32 __iomem *addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
static void pci_azx_writew(u16 value, u16 __iomem *addr)
|
||||
{
|
||||
writew(value, addr);
|
||||
}
|
||||
|
||||
static u16 pci_azx_readw(u16 __iomem *addr)
|
||||
{
|
||||
return readw(addr);
|
||||
}
|
||||
|
||||
static void pci_azx_writeb(u8 value, u8 __iomem *addr)
|
||||
{
|
||||
writeb(value, addr);
|
||||
}
|
||||
|
||||
static u8 pci_azx_readb(u8 __iomem *addr)
|
||||
{
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
static int disable_msi_reset_irq(struct azx *chip)
|
||||
{
|
||||
struct hdac_bus *bus = azx_bus(chip);
|
||||
@ -2036,24 +2008,6 @@ static int disable_msi_reset_irq(struct azx *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DMA page allocation helpers. */
|
||||
static int dma_alloc_pages(struct hdac_bus *bus,
|
||||
int type,
|
||||
size_t size,
|
||||
struct snd_dma_buffer *buf)
|
||||
{
|
||||
struct azx *chip = bus_to_azx(bus);
|
||||
|
||||
if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
|
||||
type = SNDRV_DMA_TYPE_DEV_UC;
|
||||
return snd_dma_alloc_pages(type, bus->dev, size, buf);
|
||||
}
|
||||
|
||||
static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
|
||||
{
|
||||
snd_dma_free_pages(buf);
|
||||
}
|
||||
|
||||
static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
@ -2065,23 +2019,31 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct hdac_io_ops pci_hda_io_ops = {
|
||||
.reg_writel = pci_azx_writel,
|
||||
.reg_readl = pci_azx_readl,
|
||||
.reg_writew = pci_azx_writew,
|
||||
.reg_readw = pci_azx_readw,
|
||||
.reg_writeb = pci_azx_writeb,
|
||||
.reg_readb = pci_azx_readb,
|
||||
.dma_alloc_pages = dma_alloc_pages,
|
||||
.dma_free_pages = dma_free_pages,
|
||||
};
|
||||
|
||||
static const struct hda_controller_ops pci_hda_ops = {
|
||||
.disable_msi_reset_irq = disable_msi_reset_irq,
|
||||
.pcm_mmap_prepare = pcm_mmap_prepare,
|
||||
.position_check = azx_position_check,
|
||||
};
|
||||
|
||||
static int azx_check_dmic(struct pci_dev *pci, struct azx *chip)
|
||||
{
|
||||
struct nhlt_acpi_table *nhlt;
|
||||
int ret = 0;
|
||||
|
||||
if (chip->driver_type == AZX_DRIVER_SKL &&
|
||||
pci->class != 0x040300) {
|
||||
nhlt = intel_nhlt_init(&pci->dev);
|
||||
if (nhlt) {
|
||||
if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) {
|
||||
ret = -ENODEV;
|
||||
dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n");
|
||||
}
|
||||
intel_nhlt_free(nhlt);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int azx_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
@ -2112,6 +2074,17 @@ static int azx_probe(struct pci_dev *pci,
|
||||
card->private_data = chip;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
|
||||
/*
|
||||
* stop probe if digital microphones detected on Skylake+ platform
|
||||
* with the DSP enabled. This is an opt-in behavior defined at build
|
||||
* time or at run-time with a module parameter
|
||||
*/
|
||||
if (dmic_detect) {
|
||||
err = azx_check_dmic(pci, chip);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, card);
|
||||
|
||||
err = register_vga_switcheroo(chip);
|
||||
|
@ -75,88 +75,6 @@ MODULE_PARM_DESC(power_save,
|
||||
#define power_save 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DMA page allocation ops.
|
||||
*/
|
||||
static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size,
|
||||
struct snd_dma_buffer *buf)
|
||||
{
|
||||
return snd_dma_alloc_pages(type, bus->dev, size, buf);
|
||||
}
|
||||
|
||||
static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
|
||||
{
|
||||
snd_dma_free_pages(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register access ops. Tegra HDA register access is DWORD only.
|
||||
*/
|
||||
static void hda_tegra_writel(u32 value, u32 __iomem *addr)
|
||||
{
|
||||
writel(value, addr);
|
||||
}
|
||||
|
||||
static u32 hda_tegra_readl(u32 __iomem *addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
static void hda_tegra_writew(u16 value, u16 __iomem *addr)
|
||||
{
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
u32 v;
|
||||
|
||||
v = readl(dword_addr);
|
||||
v &= ~(0xffff << shift);
|
||||
v |= value << shift;
|
||||
writel(v, dword_addr);
|
||||
}
|
||||
|
||||
static u16 hda_tegra_readw(u16 __iomem *addr)
|
||||
{
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
u32 v;
|
||||
|
||||
v = readl(dword_addr);
|
||||
return (v >> shift) & 0xffff;
|
||||
}
|
||||
|
||||
static void hda_tegra_writeb(u8 value, u8 __iomem *addr)
|
||||
{
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
u32 v;
|
||||
|
||||
v = readl(dword_addr);
|
||||
v &= ~(0xff << shift);
|
||||
v |= value << shift;
|
||||
writel(v, dword_addr);
|
||||
}
|
||||
|
||||
static u8 hda_tegra_readb(u8 __iomem *addr)
|
||||
{
|
||||
unsigned int shift = ((unsigned long)(addr) & 0x3) << 3;
|
||||
void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3);
|
||||
u32 v;
|
||||
|
||||
v = readl(dword_addr);
|
||||
return (v >> shift) & 0xff;
|
||||
}
|
||||
|
||||
static const struct hdac_io_ops hda_tegra_io_ops = {
|
||||
.reg_writel = hda_tegra_writel,
|
||||
.reg_readl = hda_tegra_readl,
|
||||
.reg_writew = hda_tegra_writew,
|
||||
.reg_readw = hda_tegra_readw,
|
||||
.reg_writeb = hda_tegra_writeb,
|
||||
.reg_readb = hda_tegra_readb,
|
||||
.dma_alloc_pages = dma_alloc_pages,
|
||||
.dma_free_pages = dma_free_pages,
|
||||
};
|
||||
|
||||
static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
|
||||
|
||||
static void hda_tegra_init(struct hda_tegra *hda)
|
||||
@ -475,7 +393,7 @@ static int hda_tegra_create(struct snd_card *card,
|
||||
|
||||
INIT_WORK(&hda->probe_work, hda_tegra_probe_work);
|
||||
|
||||
err = azx_bus_init(chip, NULL, &hda_tegra_io_ops);
|
||||
err = azx_bus_init(chip, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -51,7 +51,6 @@ source "sound/soc/dwc/Kconfig"
|
||||
source "sound/soc/fsl/Kconfig"
|
||||
source "sound/soc/hisilicon/Kconfig"
|
||||
source "sound/soc/jz4740/Kconfig"
|
||||
source "sound/soc/nuc900/Kconfig"
|
||||
source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/img/Kconfig"
|
||||
source "sound/soc/intel/Kconfig"
|
||||
|
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o
|
||||
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o
|
||||
snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o
|
||||
snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o
|
||||
|
||||
@ -39,7 +39,6 @@ obj-$(CONFIG_SND_SOC) += intel/
|
||||
obj-$(CONFIG_SND_SOC) += mediatek/
|
||||
obj-$(CONFIG_SND_SOC) += meson/
|
||||
obj-$(CONFIG_SND_SOC) += mxs/
|
||||
obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += kirkwood/
|
||||
obj-$(CONFIG_SND_SOC) += pxa/
|
||||
obj-$(CONFIG_SND_SOC) += qcom/
|
||||
|
@ -1251,8 +1251,7 @@ static int acp_audio_probe(struct platform_device *pdev)
|
||||
if (!audio_drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res);
|
||||
audio_drv_data->acp_mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(audio_drv_data->acp_mmio))
|
||||
return PTR_ERR(audio_drv_data->acp_mmio);
|
||||
|
||||
|
@ -12,25 +12,31 @@ if SND_ATMEL_SOC
|
||||
config SND_ATMEL_SOC_PDC
|
||||
tristate
|
||||
depends on HAS_DMA
|
||||
default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m
|
||||
default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y)
|
||||
|
||||
config SND_ATMEL_SOC_SSC_PDC
|
||||
tristate
|
||||
|
||||
config SND_ATMEL_SOC_DMA
|
||||
tristate
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m
|
||||
default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y)
|
||||
|
||||
config SND_ATMEL_SOC_SSC_DMA
|
||||
tristate
|
||||
|
||||
config SND_ATMEL_SOC_SSC
|
||||
tristate
|
||||
default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y
|
||||
default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m
|
||||
|
||||
config SND_ATMEL_SOC_SSC_PDC
|
||||
tristate "SoC PCM DAI support for AT91 SSC controller using PDC"
|
||||
depends on ATMEL_SSC
|
||||
select SND_ATMEL_SOC_PDC
|
||||
select SND_ATMEL_SOC_SSC
|
||||
help
|
||||
Say Y or M if you want to add support for Atmel SSC interface
|
||||
in PDC mode configured using audio-graph-card in device-tree.
|
||||
|
||||
config SND_ATMEL_SOC_SSC_DMA
|
||||
tristate "SoC PCM DAI support for AT91 SSC controller using DMA"
|
||||
depends on ATMEL_SSC
|
||||
select SND_ATMEL_SOC_DMA
|
||||
select SND_ATMEL_SOC_SSC
|
||||
help
|
||||
Say Y or M if you want to add support for Atmel SSC interface
|
||||
in DMA mode configured using audio-graph-card in device-tree.
|
||||
|
||||
config SND_AT91_SOC_SAM9G20_WM8731
|
||||
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
|
||||
|
@ -571,11 +571,8 @@ static int atmel_classd_probe(struct platform_device *pdev)
|
||||
dd->pdata = pdata;
|
||||
|
||||
dd->irq = platform_get_irq(pdev, 0);
|
||||
if (dd->irq < 0) {
|
||||
ret = dd->irq;
|
||||
dev_err(dev, "failed to could not get irq: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (dd->irq < 0)
|
||||
return dd->irq;
|
||||
|
||||
dd->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(dd->pclk)) {
|
||||
|
@ -612,11 +612,8 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
|
||||
dd->dev = dev;
|
||||
|
||||
dd->irq = platform_get_irq(pdev, 0);
|
||||
if (dd->irq < 0) {
|
||||
ret = dd->irq;
|
||||
dev_err(dev, "failed to get irq: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (dd->irq < 0)
|
||||
return dd->irq;
|
||||
|
||||
dd->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(dd->pclk)) {
|
||||
|
@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
int dir, channels, bits;
|
||||
u32 tfmr, rfmr, tcmr, rcmr;
|
||||
int ret;
|
||||
int fslen, fslen_ext;
|
||||
int fslen, fslen_ext, fs_osync, fs_edge;
|
||||
u32 cmr_div;
|
||||
u32 tcmr_period;
|
||||
u32 rcmr_period;
|
||||
@ -558,226 +558,45 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
/*
|
||||
* Compute SSC register settings.
|
||||
*/
|
||||
switch (ssc_p->daifmt
|
||||
& (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
|
||||
|
||||
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
fs_osync = SSC_FSOS_POSITIVE;
|
||||
fs_edge = SSC_START_RISING_RF;
|
||||
|
||||
rcmr = SSC_BF(RCMR_STTDLY, 0);
|
||||
tcmr = SSC_BF(TCMR_STTDLY, 0);
|
||||
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
fs_osync = SSC_FSOS_NEGATIVE;
|
||||
fs_edge = SSC_START_FALLING_RF;
|
||||
|
||||
rcmr = SSC_BF(RCMR_STTDLY, 1);
|
||||
tcmr = SSC_BF(TCMR_STTDLY, 1);
|
||||
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
/*
|
||||
* I2S format, SSC provides BCLK and LRC clocks.
|
||||
*
|
||||
* The SSC transmit and receive clocks are generated
|
||||
* from the MCK divider, and the BCLK signal
|
||||
* is output on the SSC TK line.
|
||||
*/
|
||||
|
||||
if (bits > 16 && !ssc->pdata->has_fslen_ext) {
|
||||
dev_err(dai->dev,
|
||||
"sample size %d is too large for SSC device\n",
|
||||
bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
|
||||
| SSC_BF(RFMR_FSLEN, fslen)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
|
||||
| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
|
||||
| SSC_BF(TFMR_FSLEN, fslen)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* I2S format, CODEC supplies BCLK and LRC clocks. */
|
||||
rcmr = SSC_BF(RCMR_PERIOD, 0)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_PIN : SSC_CKS_CLOCK);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(RFMR_FSLEN, 0)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, 0)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_CLOCK : SSC_CKS_PIN);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(TFMR_FSLEN, 0)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS:
|
||||
/* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */
|
||||
if (bits > 16 && !ssc->pdata->has_fslen_ext) {
|
||||
dev_err(dai->dev,
|
||||
"sample size %d is too large for SSC device\n",
|
||||
bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_PIN : SSC_CKS_CLOCK);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
|
||||
| SSC_BF(RFMR_FSLEN, fslen)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_CLOCK : SSC_CKS_PIN);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
|
||||
| SSC_BF(TFMR_FSLEN, fslen)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
|
||||
/*
|
||||
* DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
|
||||
*
|
||||
* The SSC transmit and receive clocks are generated from the
|
||||
* MCK divider, and the BCLK signal is output
|
||||
* on the SSC TK line.
|
||||
*/
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, 1)
|
||||
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE)
|
||||
| SSC_BF(RFMR_FSLEN, 0)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, 1)
|
||||
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
|
||||
| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE)
|
||||
| SSC_BF(TFMR_FSLEN, 0)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
|
||||
/*
|
||||
* DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
|
||||
* DSP/PCM Mode A format
|
||||
*
|
||||
* Data is transferred on first BCLK after LRC pulse rising
|
||||
* edge.If stereo, the right channel data is contiguous with
|
||||
* the left channel data.
|
||||
*/
|
||||
rcmr = SSC_BF(RCMR_PERIOD, 0)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_PIN : SSC_CKS_CLOCK);
|
||||
fs_osync = SSC_FSOS_POSITIVE;
|
||||
fs_edge = SSC_START_RISING_RF;
|
||||
fslen = fslen_ext = 0;
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(RFMR_FSLEN, 0)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
rcmr = SSC_BF(RCMR_STTDLY, 1);
|
||||
tcmr = SSC_BF(TCMR_STTDLY, 1);
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, 0)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_CLOCK : SSC_CKS_PIN);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(TFMR_FSLEN, 0)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -785,6 +604,70 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
ssc_p->daifmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!atmel_ssc_cfs(ssc_p)) {
|
||||
fslen = fslen_ext = 0;
|
||||
rcmr_period = tcmr_period = 0;
|
||||
fs_osync = SSC_FSOS_NONE;
|
||||
}
|
||||
|
||||
rcmr |= SSC_BF(RCMR_START, fs_edge);
|
||||
tcmr |= SSC_BF(TCMR_START, fs_edge);
|
||||
|
||||
if (atmel_ssc_cbs(ssc_p)) {
|
||||
/*
|
||||
* SSC provides BCLK
|
||||
*
|
||||
* The SSC transmit and receive clocks are generated from the
|
||||
* MCK divider, and the BCLK signal is output
|
||||
* on the SSC TK line.
|
||||
*/
|
||||
rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE);
|
||||
|
||||
tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS);
|
||||
} else {
|
||||
rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_PIN : SSC_CKS_CLOCK)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE);
|
||||
|
||||
tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
|
||||
SSC_CKS_CLOCK : SSC_CKS_PIN)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_NONE);
|
||||
}
|
||||
|
||||
rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING);
|
||||
|
||||
tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, fs_osync)
|
||||
| SSC_BF(RFMR_FSLEN, fslen)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
|
||||
| SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, fs_osync)
|
||||
| SSC_BF(TFMR_FSLEN, fslen)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
|
||||
if (fslen_ext && !ssc->pdata->has_fslen_ext) {
|
||||
dev_err(dai->dev, "sample size %d is too large for SSC device\n",
|
||||
bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("atmel_ssc_hw_params: "
|
||||
"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
|
||||
rcmr, rfmr, tcmr, tfmr);
|
||||
|
@ -392,11 +392,11 @@ static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk,
|
||||
}
|
||||
|
||||
static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
|
||||
unsigned int bclk, unsigned int *mra)
|
||||
unsigned int bclk, unsigned int *mra,
|
||||
unsigned long *best_rate)
|
||||
{
|
||||
unsigned long clk_rate;
|
||||
unsigned long lcm_rate;
|
||||
unsigned long best_rate = 0;
|
||||
unsigned long best_diff_rate = ~0;
|
||||
unsigned int sysclk;
|
||||
struct clk *best_clk = NULL;
|
||||
@ -423,7 +423,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
|
||||
(clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0));
|
||||
clk_rate += lcm_rate) {
|
||||
ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate,
|
||||
&best_clk, &best_rate,
|
||||
&best_clk, best_rate,
|
||||
&best_diff_rate);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "gclk error for rate %lu: %d",
|
||||
@ -437,7 +437,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
|
||||
}
|
||||
|
||||
ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate,
|
||||
&best_clk, &best_rate,
|
||||
&best_clk, best_rate,
|
||||
&best_diff_rate);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "pclk error for rate %lu: %d",
|
||||
@ -459,33 +459,17 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
|
||||
|
||||
dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n",
|
||||
best_clk == dev->pclk ? "pclk" : "gclk",
|
||||
best_rate, best_diff_rate);
|
||||
|
||||
/* set the rate */
|
||||
ret = clk_set_rate(best_clk, best_rate);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "unable to set rate %lu to %s: %d\n",
|
||||
best_rate, best_clk == dev->pclk ? "PCLK" : "GCLK",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
*best_rate, best_diff_rate);
|
||||
|
||||
/* Configure divisors */
|
||||
if (dev->sysclk)
|
||||
*mra |= MCHP_I2SMCC_MRA_IMCKDIV(best_rate / (2 * sysclk));
|
||||
*mra |= MCHP_I2SMCC_MRA_ISCKDIV(best_rate / (2 * bclk));
|
||||
*mra |= MCHP_I2SMCC_MRA_IMCKDIV(*best_rate / (2 * sysclk));
|
||||
*mra |= MCHP_I2SMCC_MRA_ISCKDIV(*best_rate / (2 * bclk));
|
||||
|
||||
if (best_clk == dev->gclk) {
|
||||
if (best_clk == dev->gclk)
|
||||
*mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK;
|
||||
ret = clk_prepare(dev->gclk);
|
||||
if (ret < 0)
|
||||
dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret);
|
||||
else
|
||||
dev->gclk_use = 1;
|
||||
} else {
|
||||
else
|
||||
*mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK;
|
||||
dev->gclk_use = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -502,6 +486,7 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
unsigned long rate = 0;
|
||||
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
u32 mra = 0;
|
||||
u32 mrb = 0;
|
||||
@ -640,6 +625,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (set_divs) {
|
||||
bclk_rate = frame_length * params_rate(params);
|
||||
ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra,
|
||||
&rate);
|
||||
if (ret) {
|
||||
dev_err(dev->dev,
|
||||
"unable to configure the divisors: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are already running, the wanted setup must be
|
||||
* the same with the one that's currently ongoing
|
||||
@ -656,19 +652,27 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the number of channels to know what interrupts to enable */
|
||||
dev->channels = channels;
|
||||
|
||||
if (set_divs) {
|
||||
bclk_rate = frame_length * params_rate(params);
|
||||
ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra);
|
||||
if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) {
|
||||
/* set the rate */
|
||||
ret = clk_set_rate(dev->gclk, rate);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "unable to configure the divisors: %d\n",
|
||||
ret);
|
||||
dev_err(dev->dev,
|
||||
"unable to set rate %lu to GCLK: %d\n",
|
||||
rate, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare(dev->gclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
dev->gclk_use = 1;
|
||||
}
|
||||
|
||||
/* Save the number of channels to know what interrupts to enable */
|
||||
dev->channels = channels;
|
||||
|
||||
ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra);
|
||||
if (ret < 0) {
|
||||
if (dev->gclk_use) {
|
||||
|
@ -363,7 +363,7 @@ static const struct snd_soc_component_driver au1xpsc_ac97_component = {
|
||||
static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *iores, *dmares;
|
||||
struct resource *dmares;
|
||||
unsigned long sel;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
@ -374,8 +374,7 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&wd->lock);
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
|
||||
wd->mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(wd->mmio))
|
||||
return PTR_ERR(wd->mmio);
|
||||
|
||||
|
@ -291,7 +291,7 @@ static const struct snd_soc_component_driver au1xpsc_i2s_component = {
|
||||
|
||||
static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *iores, *dmares;
|
||||
struct resource *dmares;
|
||||
unsigned long sel;
|
||||
struct au1xpsc_audio_data *wd;
|
||||
|
||||
@ -300,8 +300,7 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
|
||||
wd->mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(wd->mmio))
|
||||
return PTR_ERR(wd->mmio);
|
||||
|
||||
|
@ -828,7 +828,6 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835_i2s_dev *dev;
|
||||
int ret;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
const __be32 *addr;
|
||||
dma_addr_t dma_base;
|
||||
@ -848,8 +847,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Request ioarea */
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -639,7 +639,6 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct cygnus_aio_port *aio;
|
||||
int ret = 0;
|
||||
|
||||
aio = cygnus_dai_get_dma_data(substream);
|
||||
dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum);
|
||||
@ -647,7 +646,7 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
runtime->dma_bytes = params_buffer_bytes(params);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
@ -668,7 +667,6 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct cygnus_aio_port *aio;
|
||||
unsigned long bufsize, periodsize;
|
||||
int ret = 0;
|
||||
bool is_play;
|
||||
u32 start;
|
||||
struct ringbuf_regs *p_rbuf = NULL;
|
||||
@ -693,7 +691,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
|
||||
periodsize, bufsize);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
|
@ -1342,11 +1342,8 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
cygaud->irq_num = platform_get_irq(pdev, 0);
|
||||
if (cygaud->irq_num <= 0) {
|
||||
dev_err(dev, "platform_get_irq failed\n");
|
||||
err = cygaud->irq_num;
|
||||
return err;
|
||||
}
|
||||
if (cygaud->irq_num <= 0)
|
||||
return cygaud->irq_num;
|
||||
|
||||
err = audio_clk_init(pdev, cygaud);
|
||||
if (err) {
|
||||
|
@ -362,7 +362,6 @@ static const struct snd_soc_component_driver ep93xx_ac97_component = {
|
||||
static int ep93xx_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_ac97_info *info;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
@ -370,8 +369,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
info->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
||||
|
@ -430,15 +430,13 @@ static const struct snd_soc_component_driver ep93xx_i2s_component = {
|
||||
static int ep93xx_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_i2s_info *info;
|
||||
struct resource *res;
|
||||
int err;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
info->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
||||
|
@ -529,10 +529,6 @@ static const struct snd_kcontrol_new pm860x_snd_controls[] = {
|
||||
* DAPM Controls
|
||||
*/
|
||||
|
||||
/* PCM Switch / PCM Interface */
|
||||
static const struct snd_kcontrol_new pcm_switch_controls =
|
||||
SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
|
||||
|
||||
/* AUX1 Switch */
|
||||
static const struct snd_kcontrol_new aux1_switch_controls =
|
||||
SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
|
||||
@ -549,17 +545,6 @@ static const struct snd_kcontrol_new lepa_switch_controls =
|
||||
static const struct snd_kcontrol_new repa_switch_controls =
|
||||
SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
|
||||
|
||||
/* PCM Mux / Mux7 */
|
||||
static const char *aif1_text[] = {
|
||||
"PCM L", "PCM R",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(aif1_enum,
|
||||
PM860X_PCM_IFACE_3, 6, aif1_text);
|
||||
|
||||
static const struct snd_kcontrol_new aif1_mux =
|
||||
SOC_DAPM_ENUM("PCM Mux", aif1_enum);
|
||||
|
||||
/* I2S Mux / Mux9 */
|
||||
static const char *i2s_din_text[] = {
|
||||
"DIN", "DIN1",
|
||||
|
@ -70,10 +70,12 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_CS43130 if I2C
|
||||
select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CS4349 if I2C
|
||||
select SND_SOC_CS47L15 if MFD_CS47L15
|
||||
select SND_SOC_CS47L24 if MFD_CS47L24
|
||||
select SND_SOC_CS47L35 if MFD_CS47L35
|
||||
select SND_SOC_CS47L85 if MFD_CS47L85
|
||||
select SND_SOC_CS47L90 if MFD_CS47L90
|
||||
select SND_SOC_CS47L92 if MFD_CS47L92
|
||||
select SND_SOC_CS53L30 if I2C
|
||||
select SND_SOC_CX20442 if TTY
|
||||
select SND_SOC_CX2072X if I2C
|
||||
@ -197,6 +199,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_TS3A227E if I2C
|
||||
select SND_SOC_TWL4030 if TWL4030_CORE
|
||||
select SND_SOC_TWL6040 if TWL6040_CORE
|
||||
select SND_SOC_UDA1334 if GPIOLIB
|
||||
select SND_SOC_UDA134X
|
||||
select SND_SOC_UDA1380 if I2C
|
||||
select SND_SOC_WCD9335 if SLIMBUS
|
||||
@ -581,6 +584,9 @@ config SND_SOC_CS4349
|
||||
tristate "Cirrus Logic CS4349 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS47L15
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS47L24
|
||||
tristate
|
||||
|
||||
@ -593,6 +599,9 @@ config SND_SOC_CS47L85
|
||||
config SND_SOC_CS47L90
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS47L92
|
||||
tristate
|
||||
|
||||
# Cirrus Logic Quad-Channel ADC
|
||||
config SND_SOC_CS53L30
|
||||
tristate "Cirrus Logic CS53L30 CODEC"
|
||||
@ -722,12 +731,16 @@ config SND_SOC_LOCHNAGAR_SC
|
||||
|
||||
config SND_SOC_MADERA
|
||||
tristate
|
||||
default y if SND_SOC_CS47L15=y
|
||||
default y if SND_SOC_CS47L35=y
|
||||
default y if SND_SOC_CS47L85=y
|
||||
default y if SND_SOC_CS47L90=y
|
||||
default y if SND_SOC_CS47L92=y
|
||||
default m if SND_SOC_CS47L15=m
|
||||
default m if SND_SOC_CS47L35=m
|
||||
default m if SND_SOC_CS47L85=m
|
||||
default m if SND_SOC_CS47L90=m
|
||||
default m if SND_SOC_CS47L92=m
|
||||
|
||||
config SND_SOC_MAX98088
|
||||
tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec"
|
||||
@ -1195,6 +1208,14 @@ config SND_SOC_TWL4030
|
||||
config SND_SOC_TWL6040
|
||||
tristate
|
||||
|
||||
config SND_SOC_UDA1334
|
||||
tristate "NXP UDA1334 DAC"
|
||||
depends on GPIOLIB
|
||||
help
|
||||
The UDA1334 is an NXP audio codec, supports the I2S-bus data format
|
||||
and has basic features such as de-emphasis (at 44.1 kHz sampling
|
||||
rate) and mute.
|
||||
|
||||
config SND_SOC_UDA134X
|
||||
tristate
|
||||
|
||||
|
@ -64,10 +64,12 @@ snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-cs43130-objs := cs43130.o
|
||||
snd-soc-cs4341-objs := cs4341.o
|
||||
snd-soc-cs4349-objs := cs4349.o
|
||||
snd-soc-cs47l15-objs := cs47l15.o
|
||||
snd-soc-cs47l24-objs := cs47l24.o
|
||||
snd-soc-cs47l35-objs := cs47l35.o
|
||||
snd-soc-cs47l85-objs := cs47l85.o
|
||||
snd-soc-cs47l90-objs := cs47l90.o
|
||||
snd-soc-cs47l92-objs := cs47l92.o
|
||||
snd-soc-cs53l30-objs := cs53l30.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-cx2072x-objs := cx2072x.o
|
||||
@ -210,6 +212,7 @@ snd-soc-tscs454-objs := tscs454.o
|
||||
snd-soc-ts3a227e-objs := ts3a227e.o
|
||||
snd-soc-twl4030-objs := twl4030.o
|
||||
snd-soc-twl6040-objs := twl6040.o
|
||||
snd-soc-uda1334-objs := uda1334.o
|
||||
snd-soc-uda134x-objs := uda134x.o
|
||||
snd-soc-uda1380-objs := uda1380.o
|
||||
snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
|
||||
@ -346,9 +349,11 @@ obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o
|
||||
obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o
|
||||
obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L15) += snd-soc-cs47l15.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L35) += snd-soc-cs47l35.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o
|
||||
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o
|
||||
@ -490,6 +495,7 @@ obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o
|
||||
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
|
||||
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
|
||||
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
|
||||
obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
|
||||
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
|
||||
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
|
||||
obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
|
||||
|
@ -413,15 +413,10 @@ static struct snd_soc_dai_driver ad193x_no_adc_dai = {
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
|
||||
struct ad193x_reg_default {
|
||||
unsigned int reg;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
/* codec register values to set after reset */
|
||||
static void ad193x_reg_default_init(struct ad193x_priv *ad193x)
|
||||
{
|
||||
const struct ad193x_reg_default reg_init[] = {
|
||||
static const struct reg_sequence reg_init[] = {
|
||||
{ 0, 0x99 }, /* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */
|
||||
{ 1, 0x04 }, /* PLL_CLK_CTRL1: no on-chip Vref */
|
||||
{ 2, 0x40 }, /* DAC_CTRL0: TDM mode */
|
||||
@ -437,21 +432,17 @@ static void ad193x_reg_default_init(struct ad193x_priv *ad193x)
|
||||
{ 12, 0x00 }, /* DAC_L4_VOL: no attenuation */
|
||||
{ 13, 0x00 }, /* DAC_R4_VOL: no attenuation */
|
||||
};
|
||||
const struct ad193x_reg_default reg_adc_init[] = {
|
||||
static const struct reg_sequence reg_adc_init[] = {
|
||||
{ 14, 0x03 }, /* ADC_CTRL0: high-pass filter enable */
|
||||
{ 15, 0x43 }, /* ADC_CTRL1: sata delay=1, adc aux mode */
|
||||
{ 16, 0x00 }, /* ADC_CTRL2: reset */
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(reg_init); i++)
|
||||
regmap_write(ad193x->regmap, reg_init[i].reg, reg_init[i].val);
|
||||
regmap_multi_reg_write(ad193x->regmap, reg_init, ARRAY_SIZE(reg_init));
|
||||
|
||||
if (ad193x_has_adc(ad193x)) {
|
||||
for (i = 0; i < ARRAY_SIZE(reg_adc_init); i++) {
|
||||
regmap_write(ad193x->regmap, reg_adc_init[i].reg,
|
||||
reg_adc_init[i].val);
|
||||
}
|
||||
regmap_multi_reg_write(ad193x->regmap, reg_adc_init,
|
||||
ARRAY_SIZE(reg_adc_init));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ static struct cs4271_clk_cfg cs4271_clk_tab[] = {
|
||||
{0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2},
|
||||
};
|
||||
|
||||
#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
|
||||
#define CS4271_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
|
||||
|
||||
static int cs4271_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
@ -383,13 +383,13 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
|
||||
val = CS4271_MODE1_MODE_4X;
|
||||
|
||||
ratio = cs4271->mclk / cs4271->rate;
|
||||
for (i = 0; i < CS4171_NR_RATIOS; i++)
|
||||
for (i = 0; i < CS4271_NR_RATIOS; i++)
|
||||
if ((cs4271_clk_tab[i].master == cs4271->master) &&
|
||||
(cs4271_clk_tab[i].speed_mode == val) &&
|
||||
(cs4271_clk_tab[i].ratio == ratio))
|
||||
break;
|
||||
|
||||
if (i == CS4171_NR_RATIOS) {
|
||||
if (i == CS4271_NR_RATIOS) {
|
||||
dev_err(component->dev, "Invalid sample rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -199,14 +199,6 @@ static const struct soc_enum beep_bass_enum =
|
||||
SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
|
||||
ARRAY_SIZE(beep_bass_text), beep_bass_text);
|
||||
|
||||
static const char * const adc_swap_text[] = {
|
||||
"None", "A+B/2", "A-B/2", "Swap"
|
||||
};
|
||||
|
||||
static const struct soc_enum adc_swap_enum =
|
||||
SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
|
||||
ARRAY_SIZE(adc_swap_text), adc_swap_text);
|
||||
|
||||
static const char * const pgaa_mux_text[] = {
|
||||
"AIN1A", "AIN2A", "AIN3A"};
|
||||
|
||||
|
@ -273,12 +273,6 @@ static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum,
|
||||
CS42L73_MIXERCTL, 4,
|
||||
cs42l73_spo_mixer_text);
|
||||
|
||||
static const struct snd_kcontrol_new vsp_output_mux =
|
||||
SOC_DAPM_ENUM("Route", vsp_output_mux_enum);
|
||||
|
||||
static const struct snd_kcontrol_new xsp_output_mux =
|
||||
SOC_DAPM_ENUM("Route", xsp_output_mux_enum);
|
||||
|
||||
static const struct snd_kcontrol_new hp_amp_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1);
|
||||
|
||||
|
@ -684,6 +684,8 @@ static int cs42xx8_runtime_suspend(struct device *dev)
|
||||
#endif
|
||||
|
||||
const struct dev_pm_ops cs42xx8_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_pm);
|
||||
|
1490
sound/soc/codecs/cs47l15.c
Normal file
1490
sound/soc/codecs/cs47l15.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -524,7 +524,7 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK,
|
||||
MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, 6,
|
||||
SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT,
|
||||
0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
|
||||
|
@ -2402,13 +2402,6 @@ static irqreturn_t cs47l90_adsp2_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cs47l90_dsp_bus_error(int irq, void *data)
|
||||
{
|
||||
struct wm_adsp *dsp = (struct wm_adsp *)data;
|
||||
|
||||
return wm_adsp2_bus_error(dsp);
|
||||
}
|
||||
|
||||
static int cs47l90_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component);
|
||||
@ -2558,7 +2551,7 @@ static int cs47l90_probe(struct platform_device *pdev)
|
||||
|
||||
if (ret == 0) {
|
||||
ret = madera_init_bus_error_irq(&cs47l90->core, i,
|
||||
cs47l90_dsp_bus_error);
|
||||
wm_adsp2_bus_error);
|
||||
if (ret != 0)
|
||||
wm_adsp2_remove(&cs47l90->core.adsp[i]);
|
||||
}
|
||||
|
2039
sound/soc/codecs/cs47l92.c
Normal file
2039
sound/soc/codecs/cs47l92.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@ -33,6 +34,7 @@ static const unsigned int supported_mclk_lrck_ratios[] = {
|
||||
|
||||
struct es8316_priv {
|
||||
struct mutex lock;
|
||||
struct clk *mclk;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_jack *jack;
|
||||
@ -363,13 +365,21 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
{
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
int i;
|
||||
int i, ret;
|
||||
int count = 0;
|
||||
|
||||
es8316->sysclk = freq;
|
||||
|
||||
if (freq == 0)
|
||||
if (freq == 0) {
|
||||
es8316->sysclk_constraints.list = NULL;
|
||||
es8316->sysclk_constraints.count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(es8316->mclk, freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Limit supported sample rates to ones that can be autodetected
|
||||
* by the codec running in slave mode.
|
||||
@ -444,17 +454,10 @@ static int es8316_pcm_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (es8316->sysclk == 0) {
|
||||
dev_err(component->dev, "No sysclk provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The set of sample rates that can be supported depends on the
|
||||
* MCLK supplied to the CODEC.
|
||||
*/
|
||||
snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&es8316->sysclk_constraints);
|
||||
if (es8316->sysclk_constraints.list)
|
||||
snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&es8316->sysclk_constraints);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -466,11 +469,19 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
u8 wordlen = 0;
|
||||
int i;
|
||||
|
||||
if (!es8316->sysclk) {
|
||||
dev_err(component->dev, "No MCLK configured\n");
|
||||
return -EINVAL;
|
||||
/* Validate supported sample rates that are autodetected from MCLK */
|
||||
for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
|
||||
const unsigned int ratio = supported_mclk_lrck_ratios[i];
|
||||
|
||||
if (es8316->sysclk % ratio != 0)
|
||||
continue;
|
||||
if (es8316->sysclk / ratio == params_rate(params))
|
||||
break;
|
||||
}
|
||||
if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS)
|
||||
return -EINVAL;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
@ -700,9 +711,24 @@ static int es8316_set_jack(struct snd_soc_component *component,
|
||||
static int es8316_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
es8316->component = component;
|
||||
|
||||
es8316->mclk = devm_clk_get_optional(component->dev, "mclk");
|
||||
if (IS_ERR(es8316->mclk)) {
|
||||
dev_err(component->dev, "unable to get mclk\n");
|
||||
return PTR_ERR(es8316->mclk);
|
||||
}
|
||||
if (!es8316->mclk)
|
||||
dev_warn(component->dev, "assuming static mclk\n");
|
||||
|
||||
ret = clk_prepare_enable(es8316->mclk);
|
||||
if (ret) {
|
||||
dev_err(component->dev, "unable to enable mclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset codec and enable current state machine */
|
||||
snd_soc_component_write(component, ES8316_RESET, 0x3f);
|
||||
usleep_range(5000, 5500);
|
||||
@ -725,8 +751,16 @@ static int es8316_probe(struct snd_soc_component *component)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void es8316_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
clk_disable_unprepare(es8316->mclk);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_es8316 = {
|
||||
.probe = es8316_probe,
|
||||
.remove = es8316_remove,
|
||||
.set_jack = es8316_set_jack,
|
||||
.controls = es8316_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(es8316_snd_controls),
|
||||
|
@ -99,7 +99,6 @@ static SOC_ENUM_SINGLE_DECL(adcpol,
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
@ -274,6 +275,8 @@ struct hdmi_codec_priv {
|
||||
struct snd_pcm_chmap *chmap_info;
|
||||
unsigned int chmap_idx;
|
||||
struct mutex lock;
|
||||
struct snd_soc_jack *jack;
|
||||
unsigned int jack_status;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget hdmi_widgets[] = {
|
||||
@ -663,6 +666,49 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp,
|
||||
unsigned int jack_status)
|
||||
{
|
||||
if (hcp->jack && jack_status != hcp->jack_status) {
|
||||
snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT);
|
||||
hcp->jack_status = jack_status;
|
||||
}
|
||||
}
|
||||
|
||||
static void plugged_cb(struct device *dev, bool plugged)
|
||||
{
|
||||
struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
|
||||
|
||||
if (plugged)
|
||||
hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
|
||||
else
|
||||
hdmi_codec_jack_report(hcp, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* hdmi_codec_set_jack_detect - register HDMI plugged callback
|
||||
* @component: the hdmi-codec instance
|
||||
* @jack: ASoC jack to report (dis)connection events on
|
||||
*/
|
||||
int hdmi_codec_set_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack)
|
||||
{
|
||||
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (hcp->hcd.ops->hook_plugged_cb) {
|
||||
hcp->jack = jack;
|
||||
ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent,
|
||||
hcp->hcd.data,
|
||||
plugged_cb,
|
||||
component->dev);
|
||||
if (ret)
|
||||
hcp->jack = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hdmi_codec_set_jack_detect);
|
||||
|
||||
static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
|
||||
|
@ -405,7 +405,6 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk3036_codec_priv *priv;
|
||||
struct device_node *of_node = pdev->dev.of_node;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct regmap *grf;
|
||||
int ret;
|
||||
@ -414,8 +413,7 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -545,15 +545,13 @@ static int jz4725b_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct jz_icdc *icdc;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
|
||||
icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
|
||||
if (!icdc)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
icdc->base = devm_ioremap_resource(dev, mem);
|
||||
icdc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(icdc->base))
|
||||
return PTR_ERR(icdc->base);
|
||||
|
||||
|
@ -318,7 +318,6 @@ static int jz4740_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct jz4740_codec *jz4740_codec;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
|
||||
jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec),
|
||||
@ -326,8 +325,7 @@ static int jz4740_codec_probe(struct platform_device *pdev)
|
||||
if (!jz4740_codec)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -87,6 +87,16 @@
|
||||
#define MADERA_FLLAO_MIN_N 4
|
||||
#define MADERA_FLLAO_MAX_N 1023
|
||||
#define MADERA_FLLAO_MAX_FBDIV 254
|
||||
#define MADERA_FLLHJ_INT_MAX_N 1023
|
||||
#define MADERA_FLLHJ_INT_MIN_N 1
|
||||
#define MADERA_FLLHJ_FRAC_MAX_N 255
|
||||
#define MADERA_FLLHJ_FRAC_MIN_N 4
|
||||
#define MADERA_FLLHJ_LOW_THRESH 192000
|
||||
#define MADERA_FLLHJ_MID_THRESH 1152000
|
||||
#define MADERA_FLLHJ_MAX_THRESH 13000000
|
||||
#define MADERA_FLLHJ_LOW_GAINS 0x23f0
|
||||
#define MADERA_FLLHJ_MID_GAINS 0x22f2
|
||||
#define MADERA_FLLHJ_HIGH_GAINS 0x21f0
|
||||
|
||||
#define MADERA_FLL_SYNCHRONISER_OFFS 0x10
|
||||
#define CS47L35_FLL_SYNCHRONISER_OFFS 0xE
|
||||
@ -96,6 +106,7 @@
|
||||
#define MADERA_FLL_CONTROL_4_OFFS 0x4
|
||||
#define MADERA_FLL_CONTROL_5_OFFS 0x5
|
||||
#define MADERA_FLL_CONTROL_6_OFFS 0x6
|
||||
#define MADERA_FLL_GAIN_OFFS 0x8
|
||||
#define MADERA_FLL_CONTROL_7_OFFS 0x9
|
||||
#define MADERA_FLL_EFS_2_OFFS 0xA
|
||||
#define MADERA_FLL_SYNCHRONISER_1_OFFS 0x1
|
||||
@ -107,6 +118,9 @@
|
||||
#define MADERA_FLL_SYNCHRONISER_7_OFFS 0x7
|
||||
#define MADERA_FLL_SPREAD_SPECTRUM_OFFS 0x9
|
||||
#define MADERA_FLL_GPIO_CLOCK_OFFS 0xA
|
||||
#define MADERA_FLL_CONTROL_10_OFFS 0xA
|
||||
#define MADERA_FLL_CONTROL_11_OFFS 0xB
|
||||
#define MADERA_FLL1_DIGITAL_TEST_1_OFFS 0xD
|
||||
|
||||
#define MADERA_FLLAO_CONTROL_1_OFFS 0x1
|
||||
#define MADERA_FLLAO_CONTROL_2_OFFS 0x2
|
||||
@ -300,6 +314,100 @@ int madera_free_overheat(struct madera_priv *priv)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(madera_free_overheat);
|
||||
|
||||
static int madera_get_variable_u32_array(struct device *dev,
|
||||
const char *propname,
|
||||
u32 *dest, int n_max,
|
||||
int multiple)
|
||||
{
|
||||
int n, ret;
|
||||
|
||||
n = device_property_count_u32(dev, propname);
|
||||
if (n < 0) {
|
||||
if (n == -EINVAL)
|
||||
return 0; /* missing, ignore */
|
||||
|
||||
dev_warn(dev, "%s malformed (%d)\n", propname, n);
|
||||
|
||||
return n;
|
||||
} else if ((n % multiple) != 0) {
|
||||
dev_warn(dev, "%s not a multiple of %d entries\n",
|
||||
propname, multiple);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (n > n_max)
|
||||
n = n_max;
|
||||
|
||||
ret = device_property_read_u32_array(dev, propname, dest, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void madera_prop_get_inmode(struct madera_priv *priv)
|
||||
{
|
||||
struct madera *madera = priv->madera;
|
||||
struct madera_codec_pdata *pdata = &madera->pdata.codec;
|
||||
u32 tmp[MADERA_MAX_INPUT * MADERA_MAX_MUXED_CHANNELS];
|
||||
int n, i, in_idx, ch_idx;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode) != MADERA_MAX_INPUT);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode[0]) != MADERA_MAX_MUXED_CHANNELS);
|
||||
|
||||
n = madera_get_variable_u32_array(madera->dev, "cirrus,inmode",
|
||||
tmp, ARRAY_SIZE(tmp),
|
||||
MADERA_MAX_MUXED_CHANNELS);
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
in_idx = 0;
|
||||
ch_idx = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
pdata->inmode[in_idx][ch_idx] = tmp[i];
|
||||
|
||||
if (++ch_idx == MADERA_MAX_MUXED_CHANNELS) {
|
||||
ch_idx = 0;
|
||||
++in_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void madera_prop_get_pdata(struct madera_priv *priv)
|
||||
{
|
||||
struct madera *madera = priv->madera;
|
||||
struct madera_codec_pdata *pdata = &madera->pdata.codec;
|
||||
u32 out_mono[ARRAY_SIZE(pdata->out_mono)];
|
||||
int i, n;
|
||||
|
||||
madera_prop_get_inmode(priv);
|
||||
|
||||
n = madera_get_variable_u32_array(madera->dev, "cirrus,out-mono",
|
||||
out_mono, ARRAY_SIZE(out_mono), 1);
|
||||
if (n > 0)
|
||||
for (i = 0; i < n; ++i)
|
||||
pdata->out_mono[i] = !!out_mono[i];
|
||||
|
||||
madera_get_variable_u32_array(madera->dev,
|
||||
"cirrus,max-channels-clocked",
|
||||
pdata->max_channels_clocked,
|
||||
ARRAY_SIZE(pdata->max_channels_clocked),
|
||||
1);
|
||||
|
||||
madera_get_variable_u32_array(madera->dev, "cirrus,pdm-fmt",
|
||||
pdata->pdm_fmt,
|
||||
ARRAY_SIZE(pdata->pdm_fmt), 1);
|
||||
|
||||
madera_get_variable_u32_array(madera->dev, "cirrus,pdm-mute",
|
||||
pdata->pdm_mute,
|
||||
ARRAY_SIZE(pdata->pdm_mute), 1);
|
||||
|
||||
madera_get_variable_u32_array(madera->dev, "cirrus,dmic-ref",
|
||||
pdata->dmic_ref,
|
||||
ARRAY_SIZE(pdata->dmic_ref), 1);
|
||||
}
|
||||
|
||||
int madera_core_init(struct madera_priv *priv)
|
||||
{
|
||||
int i;
|
||||
@ -308,6 +416,9 @@ int madera_core_init(struct madera_priv *priv)
|
||||
BUILD_BUG_ON(!madera_mixer_texts[MADERA_NUM_MIXER_INPUTS - 1]);
|
||||
BUILD_BUG_ON(!madera_mixer_values[MADERA_NUM_MIXER_INPUTS - 1]);
|
||||
|
||||
if (!dev_get_platdata(priv->madera->dev))
|
||||
madera_prop_get_pdata(priv);
|
||||
|
||||
mutex_init(&priv->rate_lock);
|
||||
|
||||
for (i = 0; i < MADERA_MAX_HP_OUTPUT; i++)
|
||||
@ -944,6 +1055,10 @@ static void madera_configure_input_mode(struct madera *madera)
|
||||
int max_analogue_inputs, max_dmic_sup, i;
|
||||
|
||||
switch (madera->type) {
|
||||
case CS47L15:
|
||||
max_analogue_inputs = 1;
|
||||
max_dmic_sup = 2;
|
||||
break;
|
||||
case CS47L35:
|
||||
max_analogue_inputs = 2;
|
||||
max_dmic_sup = 2;
|
||||
@ -1770,6 +1885,18 @@ const struct soc_enum madera_asrc1_rate[] = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_asrc1_rate);
|
||||
|
||||
const struct soc_enum madera_asrc1_bidir_rate[] = {
|
||||
SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1,
|
||||
MADERA_ASRC1_RATE1_SHIFT, 0xf,
|
||||
MADERA_RATE_ENUM_SIZE,
|
||||
madera_rate_text, madera_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2,
|
||||
MADERA_ASRC1_RATE2_SHIFT, 0xf,
|
||||
MADERA_RATE_ENUM_SIZE,
|
||||
madera_rate_text, madera_rate_val),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_asrc1_bidir_rate);
|
||||
|
||||
const struct soc_enum madera_asrc2_rate[] = {
|
||||
SOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE1,
|
||||
MADERA_ASRC2_RATE1_SHIFT, 0xf,
|
||||
@ -2149,6 +2276,9 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
|
||||
switch (madera->type) {
|
||||
case CS47L90:
|
||||
case CS47L91:
|
||||
case CS42L92:
|
||||
case CS47L92:
|
||||
case CS47L93:
|
||||
out_up_delay = 6;
|
||||
break;
|
||||
default:
|
||||
@ -2264,9 +2394,17 @@ int madera_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
madera->hp_ena &= ~mask;
|
||||
madera->hp_ena |= val;
|
||||
|
||||
/* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */
|
||||
regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel);
|
||||
ep_sel &= MADERA_EP_SEL_MASK;
|
||||
switch (madera->type) {
|
||||
case CS42L92:
|
||||
case CS47L92:
|
||||
case CS47L93:
|
||||
break;
|
||||
default:
|
||||
/* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */
|
||||
regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel);
|
||||
ep_sel &= MADERA_EP_SEL_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Force off if HPDET has disabled the clamp for this output */
|
||||
if (!ep_sel &&
|
||||
@ -2442,6 +2580,58 @@ static int madera_get_dspclk_setting(struct madera *madera,
|
||||
}
|
||||
}
|
||||
|
||||
static int madera_set_outclk(struct snd_soc_component *component,
|
||||
unsigned int source, unsigned int freq)
|
||||
{
|
||||
int div, div_inc, rate;
|
||||
|
||||
switch (source) {
|
||||
case MADERA_OUTCLK_SYSCLK:
|
||||
dev_dbg(component->dev, "Configured OUTCLK to SYSCLK\n");
|
||||
snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1,
|
||||
MADERA_OUT_CLK_SRC_MASK, source);
|
||||
return 0;
|
||||
case MADERA_OUTCLK_ASYNCCLK:
|
||||
dev_dbg(component->dev, "Configured OUTCLK to ASYNCCLK\n");
|
||||
snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1,
|
||||
MADERA_OUT_CLK_SRC_MASK, source);
|
||||
return 0;
|
||||
case MADERA_OUTCLK_MCLK1:
|
||||
case MADERA_OUTCLK_MCLK2:
|
||||
case MADERA_OUTCLK_MCLK3:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (freq % 4000)
|
||||
rate = 5644800;
|
||||
else
|
||||
rate = 6144000;
|
||||
|
||||
div = 1;
|
||||
div_inc = 0;
|
||||
while (div <= 8) {
|
||||
if (freq / div == rate && !(freq % div)) {
|
||||
dev_dbg(component->dev, "Configured %dHz OUTCLK\n", rate);
|
||||
snd_soc_component_update_bits(component,
|
||||
MADERA_OUTPUT_RATE_1,
|
||||
MADERA_OUT_EXT_CLK_DIV_MASK |
|
||||
MADERA_OUT_CLK_SRC_MASK,
|
||||
(div_inc << MADERA_OUT_EXT_CLK_DIV_SHIFT) |
|
||||
source);
|
||||
return 0;
|
||||
}
|
||||
div_inc++;
|
||||
div *= 2;
|
||||
}
|
||||
|
||||
dev_err(component->dev,
|
||||
"Unable to generate %dHz OUTCLK from %dHz MCLK\n",
|
||||
rate, freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int madera_set_sysclk(struct snd_soc_component *component, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
@ -2478,6 +2668,8 @@ int madera_set_sysclk(struct snd_soc_component *component, int clk_id,
|
||||
case MADERA_CLK_OPCLK:
|
||||
case MADERA_CLK_ASYNC_OPCLK:
|
||||
return madera_set_opclk(component, clk_id, freq);
|
||||
case MADERA_CLK_OUTCLK:
|
||||
return madera_set_outclk(component, source, freq);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -2691,6 +2883,10 @@ static const unsigned int madera_sr_vals[] = {
|
||||
#define MADERA_192K_44K1_RATE_MASK 0x003E00
|
||||
#define MADERA_192K_RATE_MASK (MADERA_192K_48K_RATE_MASK | \
|
||||
MADERA_192K_44K1_RATE_MASK)
|
||||
#define MADERA_384K_48K_RATE_MASK 0x0F007E
|
||||
#define MADERA_384K_44K1_RATE_MASK 0x007E00
|
||||
#define MADERA_384K_RATE_MASK (MADERA_384K_48K_RATE_MASK | \
|
||||
MADERA_384K_44K1_RATE_MASK)
|
||||
|
||||
static const struct snd_pcm_hw_constraint_list madera_constraint = {
|
||||
.count = ARRAY_SIZE(madera_sr_vals),
|
||||
@ -2703,6 +2899,7 @@ static int madera_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];
|
||||
struct madera *madera = priv->madera;
|
||||
unsigned int base_rate;
|
||||
|
||||
if (!substream->runtime)
|
||||
@ -2722,12 +2919,26 @@ static int madera_startup(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base_rate == 0)
|
||||
dai_priv->constraint.mask = MADERA_192K_RATE_MASK;
|
||||
else if (base_rate % 4000)
|
||||
dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK;
|
||||
else
|
||||
dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK;
|
||||
switch (madera->type) {
|
||||
case CS42L92:
|
||||
case CS47L92:
|
||||
case CS47L93:
|
||||
if (base_rate == 0)
|
||||
dai_priv->constraint.mask = MADERA_384K_RATE_MASK;
|
||||
else if (base_rate % 4000)
|
||||
dai_priv->constraint.mask = MADERA_384K_44K1_RATE_MASK;
|
||||
else
|
||||
dai_priv->constraint.mask = MADERA_384K_48K_RATE_MASK;
|
||||
break;
|
||||
default:
|
||||
if (base_rate == 0)
|
||||
dai_priv->constraint.mask = MADERA_192K_RATE_MASK;
|
||||
else if (base_rate % 4000)
|
||||
dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK;
|
||||
else
|
||||
dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
@ -4048,6 +4259,308 @@ int madera_set_fll_ao_refclk(struct madera_fll *fll, int source,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(madera_set_fll_ao_refclk);
|
||||
|
||||
static int madera_fllhj_disable(struct madera_fll *fll)
|
||||
{
|
||||
struct madera *madera = fll->madera;
|
||||
bool change;
|
||||
|
||||
madera_fll_dbg(fll, "Disabling FLL\n");
|
||||
|
||||
/* Disable lockdet, but don't set ctrl_upd update but. This allows the
|
||||
* lock status bit to clear as normal, but should the FLL be enabled
|
||||
* again due to a control clock being required, the lock won't re-assert
|
||||
* as the FLL config registers are automatically applied when the FLL
|
||||
* enables.
|
||||
*/
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_11_OFFS,
|
||||
MADERA_FLL1_LOCKDET_MASK, 0);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
MADERA_FLL1_HOLD_MASK, MADERA_FLL1_HOLD_MASK);
|
||||
regmap_update_bits_check(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
MADERA_FLL1_ENA_MASK, 0, &change);
|
||||
|
||||
madera_wait_for_fll(fll, false);
|
||||
|
||||
/* ctrl_up gates the writes to all the fll's registers, setting it to 0
|
||||
* here ensures that after a runtime suspend/resume cycle when one
|
||||
* enables the fll then ctrl_up is the last bit that is configured
|
||||
* by the fll enable code rather than the cache sync operation which
|
||||
* would have updated it much earlier before writing out all fll
|
||||
* registers
|
||||
*/
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_2_OFFS,
|
||||
MADERA_FLL1_CTRL_UPD_MASK, 0);
|
||||
|
||||
if (change)
|
||||
pm_runtime_put_autosuspend(madera->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int madera_fllhj_apply(struct madera_fll *fll, int fin)
|
||||
{
|
||||
struct madera *madera = fll->madera;
|
||||
int refdiv, fref, fout, lockdet_thr, fbdiv, hp, fast_clk, fllgcd;
|
||||
bool frac = false;
|
||||
unsigned int fll_n, min_n, max_n, ratio, theta, lambda;
|
||||
unsigned int gains, val, num;
|
||||
|
||||
madera_fll_dbg(fll, "fin=%d, fout=%d\n", fin, fll->fout);
|
||||
|
||||
for (refdiv = 0; refdiv < 4; refdiv++)
|
||||
if ((fin / (1 << refdiv)) <= MADERA_FLLHJ_MAX_THRESH)
|
||||
break;
|
||||
|
||||
fref = fin / (1 << refdiv);
|
||||
|
||||
/* Use simple heuristic approach to find a configuration that
|
||||
* should work for most input clocks.
|
||||
*/
|
||||
fast_clk = 0;
|
||||
fout = fll->fout;
|
||||
frac = fout % fref;
|
||||
|
||||
if (fref < MADERA_FLLHJ_LOW_THRESH) {
|
||||
lockdet_thr = 2;
|
||||
gains = MADERA_FLLHJ_LOW_GAINS;
|
||||
if (frac)
|
||||
fbdiv = 256;
|
||||
else
|
||||
fbdiv = 4;
|
||||
} else if (fref < MADERA_FLLHJ_MID_THRESH) {
|
||||
lockdet_thr = 8;
|
||||
gains = MADERA_FLLHJ_MID_GAINS;
|
||||
fbdiv = 1;
|
||||
} else {
|
||||
lockdet_thr = 8;
|
||||
gains = MADERA_FLLHJ_HIGH_GAINS;
|
||||
fbdiv = 1;
|
||||
/* For high speed input clocks, enable 300MHz fast oscillator
|
||||
* when we're in fractional divider mode.
|
||||
*/
|
||||
if (frac) {
|
||||
fast_clk = 0x3;
|
||||
fout = fll->fout * 6;
|
||||
}
|
||||
}
|
||||
/* Use high performance mode for fractional configurations. */
|
||||
if (frac) {
|
||||
hp = 0x3;
|
||||
min_n = MADERA_FLLHJ_FRAC_MIN_N;
|
||||
max_n = MADERA_FLLHJ_FRAC_MAX_N;
|
||||
} else {
|
||||
hp = 0x0;
|
||||
min_n = MADERA_FLLHJ_INT_MIN_N;
|
||||
max_n = MADERA_FLLHJ_INT_MAX_N;
|
||||
}
|
||||
|
||||
ratio = fout / fref;
|
||||
|
||||
madera_fll_dbg(fll, "refdiv=%d, fref=%d, frac:%d\n",
|
||||
refdiv, fref, frac);
|
||||
|
||||
while (ratio / fbdiv < min_n) {
|
||||
fbdiv /= 2;
|
||||
if (fbdiv < 1) {
|
||||
madera_fll_err(fll, "FBDIV (%d) must be >= 1\n", fbdiv);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
while (frac && (ratio / fbdiv > max_n)) {
|
||||
fbdiv *= 2;
|
||||
if (fbdiv >= 1024) {
|
||||
madera_fll_err(fll, "FBDIV (%u) >= 1024\n", fbdiv);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
madera_fll_dbg(fll, "lockdet=%d, hp=0x%x, fbdiv:%d\n",
|
||||
lockdet_thr, hp, fbdiv);
|
||||
|
||||
/* Calculate N.K values */
|
||||
fllgcd = gcd(fout, fbdiv * fref);
|
||||
num = fout / fllgcd;
|
||||
lambda = (fref * fbdiv) / fllgcd;
|
||||
fll_n = num / lambda;
|
||||
theta = num % lambda;
|
||||
|
||||
madera_fll_dbg(fll, "fll_n=%d, gcd=%d, theta=%d, lambda=%d\n",
|
||||
fll_n, fllgcd, theta, lambda);
|
||||
|
||||
/* Some sanity checks before any registers are written. */
|
||||
if (fll_n < min_n || fll_n > max_n) {
|
||||
madera_fll_err(fll, "N not in valid %s mode range %d-%d: %d\n",
|
||||
frac ? "fractional" : "integer", min_n, max_n,
|
||||
fll_n);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fbdiv < 1 || (frac && fbdiv >= 1024) || (!frac && fbdiv >= 256)) {
|
||||
madera_fll_err(fll, "Invalid fbdiv for %s mode (%u)\n",
|
||||
frac ? "fractional" : "integer", fbdiv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clear the ctrl_upd bit to guarantee we write to it later. */
|
||||
regmap_write(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_2_OFFS,
|
||||
fll_n << MADERA_FLL1_N_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_3_OFFS,
|
||||
MADERA_FLL1_THETA_MASK,
|
||||
theta << MADERA_FLL1_THETA_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_4_OFFS,
|
||||
MADERA_FLL1_LAMBDA_MASK,
|
||||
lambda << MADERA_FLL1_LAMBDA_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_5_OFFS,
|
||||
MADERA_FLL1_FB_DIV_MASK,
|
||||
fbdiv << MADERA_FLL1_FB_DIV_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_6_OFFS,
|
||||
MADERA_FLL1_REFCLK_DIV_MASK,
|
||||
refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_GAIN_OFFS,
|
||||
0xffff,
|
||||
gains);
|
||||
val = hp << MADERA_FLL1_HP_SHIFT;
|
||||
val |= 1 << MADERA_FLL1_PHASEDET_ENA_SHIFT;
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_10_OFFS,
|
||||
MADERA_FLL1_HP_MASK | MADERA_FLL1_PHASEDET_ENA_MASK,
|
||||
val);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_11_OFFS,
|
||||
MADERA_FLL1_LOCKDET_THR_MASK,
|
||||
lockdet_thr << MADERA_FLL1_LOCKDET_THR_SHIFT);
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL1_DIGITAL_TEST_1_OFFS,
|
||||
MADERA_FLL1_SYNC_EFS_ENA_MASK |
|
||||
MADERA_FLL1_CLK_VCO_FAST_SRC_MASK,
|
||||
fast_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int madera_fllhj_enable(struct madera_fll *fll)
|
||||
{
|
||||
struct madera *madera = fll->madera;
|
||||
int already_enabled = madera_is_enabled_fll(fll, fll->base);
|
||||
int ret;
|
||||
|
||||
if (already_enabled < 0)
|
||||
return already_enabled;
|
||||
|
||||
if (!already_enabled)
|
||||
pm_runtime_get_sync(madera->dev);
|
||||
|
||||
madera_fll_dbg(fll, "Enabling FLL, initially %s\n",
|
||||
already_enabled ? "enabled" : "disabled");
|
||||
|
||||
/* FLLn_HOLD must be set before configuring any registers */
|
||||
regmap_update_bits(fll->madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
MADERA_FLL1_HOLD_MASK,
|
||||
MADERA_FLL1_HOLD_MASK);
|
||||
|
||||
/* Apply refclk */
|
||||
ret = madera_fllhj_apply(fll, fll->ref_freq);
|
||||
if (ret) {
|
||||
madera_fll_err(fll, "Failed to set FLL: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
CS47L92_FLL1_REFCLK_SRC_MASK,
|
||||
fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT);
|
||||
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
MADERA_FLL1_ENA_MASK,
|
||||
MADERA_FLL1_ENA_MASK);
|
||||
|
||||
out:
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_11_OFFS,
|
||||
MADERA_FLL1_LOCKDET_MASK,
|
||||
MADERA_FLL1_LOCKDET_MASK);
|
||||
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_2_OFFS,
|
||||
MADERA_FLL1_CTRL_UPD_MASK,
|
||||
MADERA_FLL1_CTRL_UPD_MASK);
|
||||
|
||||
/* Release the hold so that flln locks to external frequency */
|
||||
regmap_update_bits(madera->regmap,
|
||||
fll->base + MADERA_FLL_CONTROL_1_OFFS,
|
||||
MADERA_FLL1_HOLD_MASK,
|
||||
0);
|
||||
|
||||
if (!already_enabled)
|
||||
madera_wait_for_fll(fll, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int madera_fllhj_validate(struct madera_fll *fll,
|
||||
unsigned int ref_in,
|
||||
unsigned int fout)
|
||||
{
|
||||
if (fout && !ref_in) {
|
||||
madera_fll_err(fll, "fllout set without valid input clk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fll->fout && fout != fll->fout) {
|
||||
madera_fll_err(fll, "Can't change output on active FLL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ref_in / MADERA_FLL_MAX_REFDIV > MADERA_FLLHJ_MAX_THRESH) {
|
||||
madera_fll_err(fll, "Can't scale %dMHz to <=13MHz\n", ref_in);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int madera_fllhj_set_refclk(struct madera_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* To remain consistent with previous FLLs, we expect fout to be
|
||||
* provided in the form of the required sysclk rate, which is
|
||||
* 2x the calculated fll out.
|
||||
*/
|
||||
if (fout)
|
||||
fout /= 2;
|
||||
|
||||
if (fll->ref_src == source && fll->ref_freq == fin &&
|
||||
fll->fout == fout)
|
||||
return 0;
|
||||
|
||||
if (fin && fout && madera_fllhj_validate(fll, fin, fout))
|
||||
return -EINVAL;
|
||||
|
||||
fll->ref_src = source;
|
||||
fll->ref_freq = fin;
|
||||
fll->fout = fout;
|
||||
|
||||
if (fout)
|
||||
ret = madera_fllhj_enable(fll);
|
||||
else
|
||||
madera_fllhj_disable(fll);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(madera_fllhj_set_refclk);
|
||||
|
||||
/**
|
||||
* madera_set_output_mode - Set the mode of the specified output
|
||||
*
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define MADERA_CLK_SYSCLK_3 6
|
||||
#define MADERA_CLK_ASYNCCLK_2 7
|
||||
#define MADERA_CLK_DSPCLK 8
|
||||
#define MADERA_CLK_OUTCLK 9
|
||||
|
||||
#define MADERA_CLK_SRC_MCLK1 0x0
|
||||
#define MADERA_CLK_SRC_MCLK2 0x1
|
||||
@ -61,6 +62,12 @@
|
||||
#define MADERA_CLK_SRC_AIF4BCLK 0xB
|
||||
#define MADERA_CLK_SRC_FLLAO 0xF
|
||||
|
||||
#define MADERA_OUTCLK_SYSCLK 0
|
||||
#define MADERA_OUTCLK_ASYNCCLK 1
|
||||
#define MADERA_OUTCLK_MCLK1 4
|
||||
#define MADERA_OUTCLK_MCLK2 5
|
||||
#define MADERA_OUTCLK_MCLK3 6
|
||||
|
||||
#define MADERA_MIXER_VOL_MASK 0x00FE
|
||||
#define MADERA_MIXER_VOL_SHIFT 1
|
||||
#define MADERA_MIXER_VOL_WIDTH 7
|
||||
@ -326,6 +333,7 @@ extern const struct soc_enum madera_sample_rate[];
|
||||
extern const struct soc_enum madera_isrc_fsl[];
|
||||
extern const struct soc_enum madera_isrc_fsh[];
|
||||
extern const struct soc_enum madera_asrc1_rate[];
|
||||
extern const struct soc_enum madera_asrc1_bidir_rate[];
|
||||
extern const struct soc_enum madera_asrc2_rate[];
|
||||
extern const struct soc_enum madera_dfc_width[];
|
||||
extern const struct soc_enum madera_dfc_type[];
|
||||
@ -403,6 +411,8 @@ int madera_set_fll_syncclk(struct madera_fll *fll, int source,
|
||||
unsigned int fref, unsigned int fout);
|
||||
int madera_set_fll_ao_refclk(struct madera_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout);
|
||||
int madera_fllhj_set_refclk(struct madera_fll *fll, int source,
|
||||
unsigned int fin, unsigned int fout);
|
||||
|
||||
int madera_core_init(struct madera_priv *priv);
|
||||
int madera_core_free(struct madera_priv *priv);
|
||||
|
@ -154,10 +154,6 @@ static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv,
|
||||
8, 10, TLV_DB_SCALE_ITEM(400, 100, 0)
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv,
|
||||
0, 11, TLV_DB_SCALE_ITEM(950, 100, 0),
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
|
||||
|
||||
static const struct snd_kcontrol_new max98371_snd_controls[] = {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "max98373.h"
|
||||
@ -901,6 +902,17 @@ static void max98373_slot_config(struct i2c_client *i2c,
|
||||
else
|
||||
max98373->i_slot = 1;
|
||||
|
||||
max98373->reset_gpio = of_get_named_gpio(dev->of_node,
|
||||
"maxim,reset-gpio", 0);
|
||||
if (!gpio_is_valid(max98373->reset_gpio)) {
|
||||
dev_err(dev, "Looking up %s property in node %s failed %d\n",
|
||||
"maxim,reset-gpio", dev->of_node->full_name,
|
||||
max98373->reset_gpio);
|
||||
} else {
|
||||
dev_dbg(dev, "maxim,reset-gpio=%d",
|
||||
max98373->reset_gpio);
|
||||
}
|
||||
|
||||
if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
|
||||
max98373->spkfb_slot = value & 0xF;
|
||||
else
|
||||
@ -929,7 +941,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
||||
else
|
||||
max98373->interleave_mode = false;
|
||||
|
||||
|
||||
/* regmap initialization */
|
||||
max98373->regmap
|
||||
= devm_regmap_init_i2c(i2c, &max98373_regmap);
|
||||
@ -940,6 +951,24 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* voltage/current slot & gpio configuration */
|
||||
max98373_slot_config(i2c, max98373);
|
||||
|
||||
/* Power on device */
|
||||
if (gpio_is_valid(max98373->reset_gpio)) {
|
||||
ret = gpio_request(max98373->reset_gpio, "MAX98373_RESET");
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "%s: Failed to request gpio %d\n",
|
||||
__func__, max98373->reset_gpio);
|
||||
gpio_free(max98373->reset_gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio_direction_output(max98373->reset_gpio, 0);
|
||||
msleep(50);
|
||||
gpio_direction_output(max98373->reset_gpio, 1);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
/* Check Revision ID */
|
||||
ret = regmap_read(max98373->regmap,
|
||||
MAX98373_R21FF_REV_ID, ®);
|
||||
@ -950,9 +979,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg);
|
||||
|
||||
/* voltage/current slot configuration */
|
||||
max98373_slot_config(i2c, max98373);
|
||||
|
||||
/* codec registeration */
|
||||
ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98373,
|
||||
max98373_dai, ARRAY_SIZE(max98373_dai));
|
||||
|
@ -205,6 +205,7 @@
|
||||
|
||||
struct max98373_priv {
|
||||
struct regmap *regmap;
|
||||
int reset_gpio;
|
||||
unsigned int v_slot;
|
||||
unsigned int i_slot;
|
||||
unsigned int spkfb_slot;
|
||||
|
@ -27,19 +27,6 @@ struct max9850_priv {
|
||||
unsigned int sysclk;
|
||||
};
|
||||
|
||||
/* max9850 register cache */
|
||||
static const struct reg_default max9850_reg[] = {
|
||||
{ 2, 0x0c },
|
||||
{ 3, 0x00 },
|
||||
{ 4, 0x00 },
|
||||
{ 5, 0x00 },
|
||||
{ 6, 0x00 },
|
||||
{ 7, 0x00 },
|
||||
{ 8, 0x00 },
|
||||
{ 9, 0x00 },
|
||||
{ 10, 0x00 },
|
||||
};
|
||||
|
||||
/* these registers are not used at the moment but provided for the sake of
|
||||
* completeness */
|
||||
static bool max9850_volatile_register(struct device *dev, unsigned int reg)
|
||||
|
@ -20,15 +20,6 @@ static const char * const max98926_boost_voltage_txt[] = {
|
||||
"6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V"
|
||||
};
|
||||
|
||||
static const char * const max98926_boost_current_txt[] = {
|
||||
"0.6", "0.8", "1.0", "1.2", "1.4", "1.6", "1.8", "2.0",
|
||||
"2.2", "2.4", "2.6", "2.8", "3.2", "3.6", "4.0", "4.4"
|
||||
};
|
||||
|
||||
static const char *const max98926_dai_txt[] = {
|
||||
"Left", "Right", "LeftRight", "LeftRightDiv2",
|
||||
};
|
||||
|
||||
static const char *const max98926_pdm_ch_text[] = {
|
||||
"Current", "Voltage",
|
||||
};
|
||||
|
@ -56,7 +56,6 @@ static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
|
||||
|
||||
static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
|
||||
"A-law"};
|
||||
|
@ -1185,10 +1185,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get mbhc switch irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
pm8916_mbhc_switch_irq_handler,
|
||||
@ -1200,10 +1198,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
|
||||
|
||||
if (priv->mbhc_btn_enabled) {
|
||||
irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get button press irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
mbhc_btn_press_irq_handler,
|
||||
@ -1214,10 +1210,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "cannot request mbhc button press irq\n");
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get button release irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
mbhc_btn_release_irq_handler,
|
||||
|
@ -1143,7 +1143,6 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev)
|
||||
struct msm8916_wcd_digital_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *base;
|
||||
struct resource *mem_res;
|
||||
struct regmap *digital_map;
|
||||
int ret;
|
||||
|
||||
@ -1151,8 +1150,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, mem_res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -1066,11 +1066,6 @@ static int mt_mic_bias_2_event(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DAPM Kcontrols */
|
||||
static const struct snd_kcontrol_new mt_lineout_control =
|
||||
SOC_DAPM_SINGLE("Switch", MT6351_AUDDEC_ANA_CON3,
|
||||
RG_AUDLOLPWRUP_VAUDP32_BIT, 1, 0);
|
||||
|
||||
/* DAPM Widgets */
|
||||
static const struct snd_soc_dapm_widget mt6351_dapm_widgets[] = {
|
||||
/* Digital Clock */
|
||||
|
@ -1730,6 +1730,10 @@ static int mt6358_dmic_enable(struct mt6358_priv *priv)
|
||||
|
||||
/* UL turn on */
|
||||
regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003);
|
||||
|
||||
/* Prevent pop noise form dmic hw */
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2255,10 +2259,8 @@ static struct snd_soc_dai_driver mt6358_dai_driver[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int mt6358_codec_init_reg(struct mt6358_priv *priv)
|
||||
static void mt6358_codec_init_reg(struct mt6358_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Disable HeadphoneL/HeadphoneR short circuit protection */
|
||||
regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0,
|
||||
RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT,
|
||||
@ -2285,8 +2287,6 @@ static int mt6358_codec_init_reg(struct mt6358_priv *priv)
|
||||
/* set gpio */
|
||||
playback_gpio_reset(priv);
|
||||
capture_gpio_reset(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt6358_codec_probe(struct snd_soc_component *cmpnt)
|
||||
|
@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
|
||||
"VCCDA2"
|
||||
};
|
||||
|
||||
#define PCM3168A_DAI_DAC 0
|
||||
#define PCM3168A_DAI_ADC 1
|
||||
|
||||
/* ADC/DAC side parameters */
|
||||
struct pcm3168a_io_params {
|
||||
bool master_mode;
|
||||
unsigned int fmt;
|
||||
int tdm_slots;
|
||||
u32 tdm_mask;
|
||||
int slot_width;
|
||||
};
|
||||
|
||||
struct pcm3168a_priv {
|
||||
struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
|
||||
struct regmap *regmap;
|
||||
struct clk *scki;
|
||||
bool adc_master_mode;
|
||||
bool dac_master_mode;
|
||||
unsigned long sysclk;
|
||||
unsigned int adc_fmt;
|
||||
unsigned int dac_fmt;
|
||||
int tdm_slots;
|
||||
u32 tdm_mask[2];
|
||||
int slot_width;
|
||||
|
||||
struct pcm3168a_io_params io_params[2];
|
||||
};
|
||||
|
||||
static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
|
||||
@ -263,7 +270,7 @@ static unsigned int pcm3168a_scki_ratios[] = {
|
||||
#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios)
|
||||
#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
|
||||
|
||||
#define PCM1368A_MAX_SYSCLK 36864000
|
||||
#define PCM3168A_MAX_SYSCLK 36864000
|
||||
|
||||
static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
|
||||
{
|
||||
@ -296,7 +303,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
|
||||
int ret;
|
||||
|
||||
if (freq > PCM1368A_MAX_SYSCLK)
|
||||
if (freq > PCM3168A_MAX_SYSCLK)
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_set_rate(pcm3168a->scki, freq);
|
||||
@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
unsigned int format, bool dac)
|
||||
static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dac) {
|
||||
if (dai->id == PCM3168A_DAI_DAC) {
|
||||
reg = PCM3168A_DAC_PWR_MST_FMT;
|
||||
mask = PCM3168A_DAC_FMT_MASK;
|
||||
shift = PCM3168A_DAC_FMT_SHIFT;
|
||||
pcm3168a->dac_master_mode = master_mode;
|
||||
pcm3168a->dac_fmt = fmt;
|
||||
} else {
|
||||
reg = PCM3168A_ADC_MST_FMT;
|
||||
mask = PCM3168A_ADC_FMTAD_MASK;
|
||||
shift = PCM3168A_ADC_FMTAD_SHIFT;
|
||||
pcm3168a->adc_master_mode = master_mode;
|
||||
pcm3168a->adc_fmt = fmt;
|
||||
}
|
||||
|
||||
pcm3168a->io_params[dai->id].master_mode = master_mode;
|
||||
pcm3168a->io_params[dai->id].fmt = fmt;
|
||||
|
||||
regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
|
||||
unsigned int format)
|
||||
{
|
||||
return pcm3168a_set_dai_fmt(dai, format, true);
|
||||
}
|
||||
|
||||
static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
|
||||
unsigned int format)
|
||||
{
|
||||
return pcm3168a_set_dai_fmt(dai, format, false);
|
||||
}
|
||||
|
||||
static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots,
|
||||
int slot_width)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
|
||||
|
||||
if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
|
||||
dev_err(component->dev,
|
||||
@ -408,22 +402,13 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pcm3168a->tdm_slots && pcm3168a->tdm_slots != slots) {
|
||||
dev_err(component->dev, "Not matching slots %d vs %d\n",
|
||||
pcm3168a->tdm_slots, slots);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) {
|
||||
dev_err(component->dev, "Not matching slot_width %d vs %d\n",
|
||||
pcm3168a->slot_width, slot_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pcm3168a->tdm_slots = slots;
|
||||
pcm3168a->slot_width = slot_width;
|
||||
pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
|
||||
pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
|
||||
io_params->tdm_slots = slots;
|
||||
io_params->slot_width = slot_width;
|
||||
/* Ignore the not relevant mask for the DAI/direction */
|
||||
if (dai->id == PCM3168A_DAI_DAC)
|
||||
io_params->tdm_mask = tx_mask;
|
||||
else
|
||||
io_params->tdm_mask = rx_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -434,7 +419,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
bool tx, master_mode;
|
||||
struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
|
||||
bool master_mode;
|
||||
u32 val, mask, shift, reg;
|
||||
unsigned int rate, fmt, ratio, max_ratio;
|
||||
unsigned int tdm_slots;
|
||||
@ -444,23 +430,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
ratio = pcm3168a->sysclk / rate;
|
||||
|
||||
tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
if (tx) {
|
||||
if (dai->id == PCM3168A_DAI_DAC) {
|
||||
max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
|
||||
reg = PCM3168A_DAC_PWR_MST_FMT;
|
||||
mask = PCM3168A_DAC_MSDA_MASK;
|
||||
shift = PCM3168A_DAC_MSDA_SHIFT;
|
||||
master_mode = pcm3168a->dac_master_mode;
|
||||
fmt = pcm3168a->dac_fmt;
|
||||
} else {
|
||||
max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
|
||||
reg = PCM3168A_ADC_MST_FMT;
|
||||
mask = PCM3168A_ADC_MSAD_MASK;
|
||||
shift = PCM3168A_ADC_MSAD_SHIFT;
|
||||
master_mode = pcm3168a->adc_master_mode;
|
||||
fmt = pcm3168a->adc_fmt;
|
||||
}
|
||||
|
||||
master_mode = io_params->master_mode;
|
||||
fmt = io_params->fmt;
|
||||
|
||||
for (i = 0; i < max_ratio; i++) {
|
||||
if (pcm3168a_scki_ratios[i] == ratio)
|
||||
break;
|
||||
@ -471,8 +455,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pcm3168a->slot_width)
|
||||
slot_width = pcm3168a->slot_width;
|
||||
if (io_params->slot_width)
|
||||
slot_width = io_params->slot_width;
|
||||
else
|
||||
slot_width = params_width(params);
|
||||
|
||||
@ -497,8 +481,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pcm3168a->tdm_slots)
|
||||
tdm_slots = pcm3168a->tdm_slots;
|
||||
if (io_params->tdm_slots)
|
||||
tdm_slots = io_params->tdm_slots;
|
||||
else
|
||||
tdm_slots = params_channels(params);
|
||||
|
||||
@ -534,7 +518,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
regmap_update_bits(pcm3168a->regmap, reg, mask, val);
|
||||
|
||||
if (tx) {
|
||||
if (dai->id == PCM3168A_DAI_DAC) {
|
||||
mask = PCM3168A_DAC_FMT_MASK;
|
||||
shift = PCM3168A_DAC_FMT_SHIFT;
|
||||
} else {
|
||||
@ -552,20 +536,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
unsigned int fmt;
|
||||
unsigned int sample_min;
|
||||
unsigned int channel_max;
|
||||
unsigned int channel_maxs[] = {
|
||||
6, /* rx */
|
||||
8 /* tx */
|
||||
8, /* DAC */
|
||||
6 /* ADC */
|
||||
};
|
||||
|
||||
if (tx)
|
||||
fmt = pcm3168a->dac_fmt;
|
||||
else
|
||||
fmt = pcm3168a->adc_fmt;
|
||||
|
||||
/*
|
||||
* Available Data Bits
|
||||
*
|
||||
@ -578,7 +555,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
* I2S
|
||||
* LEFT_J
|
||||
*/
|
||||
switch (fmt) {
|
||||
switch (pcm3168a->io_params[dai->id].fmt) {
|
||||
case PCM3168A_FMT_RIGHT_J:
|
||||
sample_min = 16;
|
||||
channel_max = 2;
|
||||
@ -588,7 +565,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
case PCM3168A_FMT_DSP_A:
|
||||
case PCM3168A_FMT_DSP_B:
|
||||
sample_min = 24;
|
||||
channel_max = channel_maxs[tx];
|
||||
channel_max = channel_maxs[dai->id];
|
||||
break;
|
||||
default:
|
||||
sample_min = 24;
|
||||
@ -599,32 +576,29 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
|
||||
sample_min, 32);
|
||||
|
||||
/* Allow all channels in multi DIN/DOUT mode */
|
||||
if (pcm3168a->io_params[dai->id].tdm_slots == 2)
|
||||
channel_max = channel_maxs[dai->id];
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
2, channel_max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
|
||||
static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
|
||||
.startup = pcm3168a_startup,
|
||||
.set_fmt = pcm3168a_set_dai_fmt_dac,
|
||||
.set_fmt = pcm3168a_set_dai_fmt,
|
||||
.set_sysclk = pcm3168a_set_dai_sysclk,
|
||||
.hw_params = pcm3168a_hw_params,
|
||||
.digital_mute = pcm3168a_digital_mute,
|
||||
.set_tdm_slot = pcm3168a_set_tdm_slot,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
|
||||
.startup = pcm3168a_startup,
|
||||
.set_fmt = pcm3168a_set_dai_fmt_adc,
|
||||
.set_sysclk = pcm3168a_set_dai_sysclk,
|
||||
.hw_params = pcm3168a_hw_params,
|
||||
.set_tdm_slot = pcm3168a_set_tdm_slot,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver pcm3168a_dais[] = {
|
||||
{
|
||||
.name = "pcm3168a-dac",
|
||||
.id = PCM3168A_DAI_DAC,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
@ -632,10 +606,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = PCM3168A_FORMATS
|
||||
},
|
||||
.ops = &pcm3168a_dac_dai_ops
|
||||
.ops = &pcm3168a_dai_ops
|
||||
},
|
||||
{
|
||||
.name = "pcm3168a-adc",
|
||||
.id = PCM3168A_DAI_ADC,
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
@ -643,7 +618,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = PCM3168A_FORMATS
|
||||
},
|
||||
.ops = &pcm3168a_adc_dai_ops
|
||||
.ops = &pcm3168a_dai_ops
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -432,7 +432,6 @@ static int rk3328_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *rk3328_np = pdev->dev.of_node;
|
||||
struct rk3328_codec_priv *rk3328;
|
||||
struct resource *res;
|
||||
struct regmap *grf;
|
||||
void __iomem *base;
|
||||
int ret = 0;
|
||||
@ -482,8 +481,7 @@ static int rk3328_platform_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -978,9 +978,6 @@ static bool rt1011_readable_register(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9435, 37, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1739, 37, 0);
|
||||
|
||||
static const char * const rt1011_din_source_select[] = {
|
||||
"Left",
|
||||
"Right",
|
||||
@ -1029,6 +1026,8 @@ static const char * const rt1011_tdm_adc_swap_select[] = {
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc1_1_enum, RT1011_TDM1_SET_3, 6,
|
||||
rt1011_tdm_adc_swap_select);
|
||||
static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc2_1_enum, RT1011_TDM1_SET_3, 4,
|
||||
rt1011_tdm_adc_swap_select);
|
||||
|
||||
static void rt1011_reset(struct regmap *regmap)
|
||||
{
|
||||
@ -1223,7 +1222,10 @@ static int rt1011_bq_drc_info(struct snd_kcontrol *kcontrol,
|
||||
static int rt1011_r0_cali_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
ucontrol->value.integer.value[0] = 0;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.integer.value[0] = rt1011->cali_done;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1237,6 +1239,7 @@ static int rt1011_r0_cali_put(struct snd_kcontrol *kcontrol,
|
||||
if (!component->card->instantiated)
|
||||
return 0;
|
||||
|
||||
rt1011->cali_done = 0;
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF &&
|
||||
ucontrol->value.integer.value[0])
|
||||
rt1011_calibrate(rt1011, 1);
|
||||
@ -1333,7 +1336,8 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = {
|
||||
/* TDM1 Data Out Selection */
|
||||
SOC_ENUM("TDM1 DOUT Source", rt1011_tdm1_adc1_dat_enum),
|
||||
SOC_ENUM("TDM1 DOUT Location", rt1011_tdm1_adc1_loc_enum),
|
||||
SOC_ENUM("TDM1 ADCDAT Swap Select", rt1011_tdm_adc1_1_enum),
|
||||
SOC_ENUM("TDM1 ADC1DAT Swap Select", rt1011_tdm_adc1_1_enum),
|
||||
SOC_ENUM("TDM1 ADC2DAT Swap Select", rt1011_tdm_adc2_1_enum),
|
||||
|
||||
/* Data Out Mode */
|
||||
SOC_ENUM("I2S ADC DOUT Mode", rt1011_adc_dout_mode_enum),
|
||||
@ -1355,6 +1359,10 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = {
|
||||
SOC_SINGLE_EXT("R0 Calibration", SND_SOC_NOPM, 0, 1, 0,
|
||||
rt1011_r0_cali_get, rt1011_r0_cali_put),
|
||||
RT1011_R0_LOAD("R0 Load Mode"),
|
||||
|
||||
/* R0 temperature */
|
||||
SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP,
|
||||
2, 255, 0),
|
||||
};
|
||||
|
||||
static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
|
||||
@ -1511,7 +1519,8 @@ static const struct snd_soc_dapm_route rt1011_dapm_routes[] = {
|
||||
|
||||
static int rt1011_get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
int i;
|
||||
static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
@ -2139,6 +2148,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag)
|
||||
r0_factor = ((format / r0[0] * 100) / 128)
|
||||
- (r0_integer * 100);
|
||||
rt1011->r0_reg = r0[0];
|
||||
rt1011->cali_done = 1;
|
||||
dev_info(dev, "r0 resistance about %d.%02d ohm, reg=0x%X\n",
|
||||
r0_integer, r0_factor, r0[0]);
|
||||
}
|
||||
@ -2189,6 +2199,13 @@ static void rt1011_calibration_work(struct work_struct *work)
|
||||
|
||||
rt1011_calibrate(rt1011, 1);
|
||||
|
||||
/*
|
||||
* This flag should reset after booting.
|
||||
* The factory test will do calibration again and use this flag to check
|
||||
* whether the calibration completed
|
||||
*/
|
||||
rt1011->cali_done = 0;
|
||||
|
||||
/* initial */
|
||||
rt1011_reg_init(component);
|
||||
}
|
||||
|
@ -227,6 +227,7 @@
|
||||
#define RT1011_STP_CALIB_RS_TEMP 0x152a
|
||||
#define RT1011_INIT_RECIPROCAL_REG_24_16 0x1538
|
||||
#define RT1011_INIT_RECIPROCAL_REG_15_0 0x1539
|
||||
#define RT1011_STP_INITIAL_RESISTANCE_TEMP 0x153c
|
||||
#define RT1011_STP_ALPHA_RECIPROCAL_MSB 0x153e
|
||||
#define RT1011_SPK_RESISTANCE_1 0x1544
|
||||
#define RT1011_SPK_RESISTANCE_2 0x1546
|
||||
@ -665,7 +666,7 @@ struct rt1011_priv {
|
||||
int pll_out;
|
||||
|
||||
int bq_drc_set;
|
||||
unsigned int r0_reg;
|
||||
unsigned int r0_reg, cali_done;
|
||||
int recv_spk_mode;
|
||||
};
|
||||
|
||||
|
@ -608,7 +608,8 @@ static const struct snd_soc_dapm_route rt1305_dapm_routes[] = {
|
||||
|
||||
static int rt1305_get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
int i;
|
||||
static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -1,13 +1,10 @@
|
||||
/*
|
||||
* rt1308.c -- RT1308 ALSA SoC amplifier component driver
|
||||
*
|
||||
* Copyright 2019 Realtek Semiconductor Corp.
|
||||
* Author: Derek Fang <derek.fang@realtek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// rt1308.c -- RT1308 ALSA SoC amplifier component driver
|
||||
//
|
||||
// Copyright 2019 Realtek Semiconductor Corp.
|
||||
// Author: Derek Fang <derek.fang@realtek.com>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -40,10 +37,10 @@ static const struct reg_sequence init_list[] = {
|
||||
{ RT1308_VREF, 0x18100000 },
|
||||
{ RT1308_IV_SENSE, 0x87010000 },
|
||||
{ RT1308_DUMMY_REG, 0x00000200 },
|
||||
{ RT1308_SIL_DET, 0x61c30000 },
|
||||
{ RT1308_SIL_DET, 0xe1c30000 },
|
||||
{ RT1308_DC_CAL_2, 0x00ffff00 },
|
||||
{ RT1308_CLK_DET, 0x01000000 },
|
||||
{ RT1308_POWER_STATUS, 0x00800000 },
|
||||
{ RT1308_POWER_STATUS, 0x08800000 },
|
||||
{ RT1308_DAC_SET, 0xafaf0700 },
|
||||
|
||||
};
|
||||
@ -308,12 +305,13 @@ static int rt1308_classd_event(struct snd_soc_dapm_widget *w,
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
msleep(30);
|
||||
snd_soc_component_update_bits(component, RT1308_POWER_STATUS,
|
||||
RT1308_POW_PDB_REG_BIT, RT1308_POW_PDB_REG_BIT);
|
||||
RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT,
|
||||
RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT);
|
||||
msleep(40);
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_component_update_bits(component, RT1308_POWER_STATUS,
|
||||
RT1308_POW_PDB_REG_BIT, 0);
|
||||
RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT, 0);
|
||||
usleep_range(150000, 200000);
|
||||
break;
|
||||
|
||||
@ -438,7 +436,8 @@ static const struct snd_soc_dapm_route rt1308_dapm_routes[] = {
|
||||
|
||||
static int rt1308_get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
int i;
|
||||
static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
@ -808,33 +807,11 @@ static void rt1308_efuse(struct rt1308_priv *rt1308)
|
||||
{
|
||||
regmap_write(rt1308->regmap, RT1308_RESET, 0);
|
||||
|
||||
regmap_write(rt1308->regmap, RT1308_POWER, 0xff371600);
|
||||
regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52100000);
|
||||
regmap_write(rt1308->regmap, RT1308_I2C_I2S_SDW_SET, 0x01014005);
|
||||
regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501);
|
||||
regmap_write(rt1308->regmap, RT1308_PADS_1, 0x50150505);
|
||||
regmap_write(rt1308->regmap, RT1308_VREF, 0x18100000);
|
||||
regmap_write(rt1308->regmap, RT1308_IV_SENSE, 0x87010000);
|
||||
regmap_write(rt1308->regmap, RT1308_DUMMY_REG, 0x00000200);
|
||||
regmap_write(rt1308->regmap, RT1308_SIL_DET, 0x61c30000);
|
||||
regmap_write(rt1308->regmap, RT1308_CLK_DET, 0x03700000);
|
||||
regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x50022f00);
|
||||
regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x01800000);
|
||||
regmap_write(rt1308->regmap, RT1308_DC_CAL_2, 0x00ffff00);
|
||||
regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x607e5501);
|
||||
|
||||
regmap_write(rt1308->regmap, RT1308_CLK_2, 0x0060e000);
|
||||
regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x04fe0f00);
|
||||
msleep(100);
|
||||
regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x44fe0f00);
|
||||
msleep(20);
|
||||
regmap_write(rt1308->regmap, RT1308_PVDD_OFFSET_CTL, 0x10000000);
|
||||
|
||||
regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x00800000);
|
||||
regmap_write(rt1308->regmap, RT1308_POWER, 0x0);
|
||||
regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52000000);
|
||||
regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501);
|
||||
regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x10022f00);
|
||||
}
|
||||
|
||||
static int rt1308_i2c_probe(struct i2c_client *i2c,
|
||||
|
@ -1,12 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* RT1308.h -- RT1308 ALSA SoC amplifier component driver
|
||||
* rt1308.h -- RT1308 ALSA SoC amplifier component driver
|
||||
*
|
||||
* Copyright 2019 Realtek Semiconductor Corp.
|
||||
* Author: Derek Fang <derek.fang@realtek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _RT1308_H_
|
||||
|
@ -2566,7 +2566,7 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
|
||||
static int rt5665_set_verf(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
@ -2686,11 +2686,11 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL,
|
||||
RT5665_PWR_MIC_DET_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0,
|
||||
rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0,
|
||||
rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0,
|
||||
rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
|
||||
/* ASRC */
|
||||
SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1,
|
||||
|
@ -691,10 +691,12 @@ static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on)
|
||||
struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (on) {
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
|
||||
RT5677_PWR_DSP, RT5677_PWR_DSP);
|
||||
rt5677->is_dsp_mode = true;
|
||||
} else {
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
|
||||
RT5677_PWR_DSP, 0x0);
|
||||
rt5677->is_dsp_mode = false;
|
||||
}
|
||||
}
|
||||
@ -4466,7 +4468,8 @@ static int rt5677_set_bias_level(struct snd_soc_component *component,
|
||||
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
|
||||
RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
|
||||
0x0055);
|
||||
5 << RT5677_LDO1_SEL_SFT |
|
||||
5 << RT5677_LDO2_SEL_SFT);
|
||||
regmap_update_bits(rt5677->regmap,
|
||||
RT5677_PR_BASE + RT5677_BIAS_CUR4,
|
||||
0x0f00, 0x0f00);
|
||||
@ -4490,9 +4493,11 @@ static int rt5677_set_bias_level(struct snd_soc_component *component,
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 0x0022);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_ANLG1,
|
||||
2 << RT5677_LDO1_SEL_SFT |
|
||||
2 << RT5677_LDO2_SEL_SFT);
|
||||
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
|
||||
RT5677_PWR_CORE, 0);
|
||||
regmap_update_bits(rt5677->regmap,
|
||||
RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
|
||||
|
||||
@ -4719,7 +4724,8 @@ static int rt5677_probe(struct snd_soc_component *component)
|
||||
|
||||
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
|
||||
~RT5677_IRQ_DEBOUNCE_SEL_MASK, 0x0020);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
|
||||
regmap_write(rt5677->regmap, RT5677_PWR_DSP2,
|
||||
RT5677_PWR_SLIM_ISO | RT5677_PWR_CORE_ISO);
|
||||
|
||||
for (i = 0; i < RT5677_GPIO_NUM; i++)
|
||||
rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
|
||||
|
@ -31,6 +31,13 @@
|
||||
#define SGTL5000_DAP_REG_OFFSET 0x0100
|
||||
#define SGTL5000_MAX_REG_OFFSET 0x013A
|
||||
|
||||
/* Delay for the VAG ramp up */
|
||||
#define SGTL5000_VAG_POWERUP_DELAY 500 /* ms */
|
||||
/* Delay for the VAG ramp down */
|
||||
#define SGTL5000_VAG_POWERDOWN_DELAY 500 /* ms */
|
||||
|
||||
#define SGTL5000_OUTPUTS_MUTE (SGTL5000_HP_MUTE | SGTL5000_LINE_OUT_MUTE)
|
||||
|
||||
/* default value of sgtl5000 registers */
|
||||
static const struct reg_default sgtl5000_reg_defaults[] = {
|
||||
{ SGTL5000_CHIP_DIG_POWER, 0x0000 },
|
||||
@ -123,6 +130,13 @@ enum {
|
||||
I2S_SCLK_STRENGTH_HIGH,
|
||||
};
|
||||
|
||||
enum {
|
||||
HP_POWER_EVENT,
|
||||
DAC_POWER_EVENT,
|
||||
ADC_POWER_EVENT,
|
||||
LAST_POWER_EVENT = ADC_POWER_EVENT
|
||||
};
|
||||
|
||||
/* sgtl5000 private structure in codec */
|
||||
struct sgtl5000_priv {
|
||||
int sysclk; /* sysclk rate */
|
||||
@ -137,8 +151,109 @@ struct sgtl5000_priv {
|
||||
u8 micbias_voltage;
|
||||
u8 lrclk_strength;
|
||||
u8 sclk_strength;
|
||||
u16 mute_state[LAST_POWER_EVENT + 1];
|
||||
};
|
||||
|
||||
static inline int hp_sel_input(struct snd_soc_component *component)
|
||||
{
|
||||
return (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_CTRL) &
|
||||
SGTL5000_HP_SEL_MASK) >> SGTL5000_HP_SEL_SHIFT;
|
||||
}
|
||||
|
||||
static inline u16 mute_output(struct snd_soc_component *component,
|
||||
u16 mute_mask)
|
||||
{
|
||||
u16 mute_reg = snd_soc_component_read32(component,
|
||||
SGTL5000_CHIP_ANA_CTRL);
|
||||
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL,
|
||||
mute_mask, mute_mask);
|
||||
return mute_reg;
|
||||
}
|
||||
|
||||
static inline void restore_output(struct snd_soc_component *component,
|
||||
u16 mute_mask, u16 mute_reg)
|
||||
{
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL,
|
||||
mute_mask, mute_reg);
|
||||
}
|
||||
|
||||
static void vag_power_on(struct snd_soc_component *component, u32 source)
|
||||
{
|
||||
if (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) &
|
||||
SGTL5000_VAG_POWERUP)
|
||||
return;
|
||||
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
|
||||
|
||||
/* When VAG powering on to get local loop from Line-In, the sleep
|
||||
* is required to avoid loud pop.
|
||||
*/
|
||||
if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN &&
|
||||
source == HP_POWER_EVENT)
|
||||
msleep(SGTL5000_VAG_POWERUP_DELAY);
|
||||
}
|
||||
|
||||
static int vag_power_consumers(struct snd_soc_component *component,
|
||||
u16 ana_pwr_reg, u32 source)
|
||||
{
|
||||
int consumers = 0;
|
||||
|
||||
/* count dac/adc consumers unconditional */
|
||||
if (ana_pwr_reg & SGTL5000_DAC_POWERUP)
|
||||
consumers++;
|
||||
if (ana_pwr_reg & SGTL5000_ADC_POWERUP)
|
||||
consumers++;
|
||||
|
||||
/*
|
||||
* If the event comes from HP and Line-In is selected,
|
||||
* current action is 'DAC to be powered down'.
|
||||
* As HP_POWERUP is not set when HP muxed to line-in,
|
||||
* we need to keep VAG power ON.
|
||||
*/
|
||||
if (source == HP_POWER_EVENT) {
|
||||
if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN)
|
||||
consumers++;
|
||||
} else {
|
||||
if (ana_pwr_reg & SGTL5000_HP_POWERUP)
|
||||
consumers++;
|
||||
}
|
||||
|
||||
return consumers;
|
||||
}
|
||||
|
||||
static void vag_power_off(struct snd_soc_component *component, u32 source)
|
||||
{
|
||||
u16 ana_pwr = snd_soc_component_read32(component,
|
||||
SGTL5000_CHIP_ANA_POWER);
|
||||
|
||||
if (!(ana_pwr & SGTL5000_VAG_POWERUP))
|
||||
return;
|
||||
|
||||
/*
|
||||
* This function calls when any of VAG power consumers is disappearing.
|
||||
* Thus, if there is more than one consumer at the moment, as minimum
|
||||
* one consumer will definitely stay after the end of the current
|
||||
* event.
|
||||
* Don't clear VAG_POWERUP if 2 or more consumers of VAG present:
|
||||
* - LINE_IN (for HP events) / HP (for DAC/ADC events)
|
||||
* - DAC
|
||||
* - ADC
|
||||
* (the current consumer is disappearing right now)
|
||||
*/
|
||||
if (vag_power_consumers(component, ana_pwr, source) >= 2)
|
||||
return;
|
||||
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP, 0);
|
||||
/* In power down case, we need wait 400-1000 ms
|
||||
* when VAG fully ramped down.
|
||||
* As longer we wait, as smaller pop we've got.
|
||||
*/
|
||||
msleep(SGTL5000_VAG_POWERDOWN_DELAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* mic_bias power on/off share the same register bits with
|
||||
* output impedance of mic bias, when power on mic bias, we
|
||||
@ -170,36 +285,46 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* As manual described, ADC/DAC only works when VAG powerup,
|
||||
* So enabled VAG before ADC/DAC up.
|
||||
* In power down case, we need wait 400ms when vag fully ramped down.
|
||||
*/
|
||||
static int power_vag_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
static int vag_and_mute_control(struct snd_soc_component *component,
|
||||
int event, int event_source)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
|
||||
static const u16 mute_mask[] = {
|
||||
/*
|
||||
* Mask for HP_POWER_EVENT.
|
||||
* Muxing Headphones have to be wrapped with mute/unmute
|
||||
* headphones only.
|
||||
*/
|
||||
SGTL5000_HP_MUTE,
|
||||
/*
|
||||
* Masks for DAC_POWER_EVENT/ADC_POWER_EVENT.
|
||||
* Muxing DAC or ADC block have to wrapped with mute/unmute
|
||||
* both headphones and line-out.
|
||||
*/
|
||||
SGTL5000_OUTPUTS_MUTE,
|
||||
SGTL5000_OUTPUTS_MUTE
|
||||
};
|
||||
|
||||
struct sgtl5000_priv *sgtl5000 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
|
||||
msleep(400);
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
sgtl5000->mute_state[event_source] =
|
||||
mute_output(component, mute_mask[event_source]);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
vag_power_on(component, event_source);
|
||||
restore_output(component, mute_mask[event_source],
|
||||
sgtl5000->mute_state[event_source]);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
/*
|
||||
* Don't clear VAG_POWERUP, when both DAC and ADC are
|
||||
* operational to prevent inadvertently starving the
|
||||
* other one of them.
|
||||
*/
|
||||
if ((snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) &
|
||||
mask) != mask) {
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP, 0);
|
||||
msleep(400);
|
||||
}
|
||||
sgtl5000->mute_state[event_source] =
|
||||
mute_output(component, mute_mask[event_source]);
|
||||
vag_power_off(component, event_source);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
restore_output(component, mute_mask[event_source],
|
||||
sgtl5000->mute_state[event_source]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -208,6 +333,41 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mute Headphone when power it up/down.
|
||||
* Control VAG power on HP power path.
|
||||
*/
|
||||
static int headphone_pga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
|
||||
return vag_and_mute_control(component, event, HP_POWER_EVENT);
|
||||
}
|
||||
|
||||
/* As manual describes, ADC/DAC powering up/down requires
|
||||
* to mute outputs to avoid pops.
|
||||
* Control VAG power on ADC/DAC power path.
|
||||
*/
|
||||
static int adc_updown_depop(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
|
||||
return vag_and_mute_control(component, event, ADC_POWER_EVENT);
|
||||
}
|
||||
|
||||
static int dac_updown_depop(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(w->dapm);
|
||||
|
||||
return vag_and_mute_control(component, event, DAC_POWER_EVENT);
|
||||
}
|
||||
|
||||
/* input sources for ADC */
|
||||
static const char *adc_mux_text[] = {
|
||||
"MIC_IN", "LINE_IN"
|
||||
@ -280,7 +440,10 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
|
||||
mic_bias_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
|
||||
SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0,
|
||||
headphone_pga_event,
|
||||
SND_SOC_DAPM_PRE_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
|
||||
@ -301,11 +464,12 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
|
||||
0, SGTL5000_CHIP_DIG_POWER,
|
||||
1, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
|
||||
|
||||
SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event),
|
||||
SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event),
|
||||
SND_SOC_DAPM_ADC_E("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0,
|
||||
adc_updown_depop, SND_SOC_DAPM_PRE_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_POST_PMD),
|
||||
SND_SOC_DAPM_DAC_E("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0,
|
||||
dac_updown_depop, SND_SOC_DAPM_PRE_POST_PMU |
|
||||
SND_SOC_DAPM_PRE_POST_PMD),
|
||||
};
|
||||
|
||||
/* routes for sgtl5000 */
|
||||
@ -556,6 +720,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
|
||||
SGTL5000_CHIP_ANA_ADC_CTRL,
|
||||
8, 1, 0, capture_6db_attenuate),
|
||||
SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0),
|
||||
SOC_SINGLE("Capture Switch", SGTL5000_CHIP_ANA_CTRL, 0, 1, 1),
|
||||
|
||||
SOC_DOUBLE_TLV("Headphone Playback Volume",
|
||||
SGTL5000_CHIP_ANA_HP_CTRL,
|
||||
@ -1173,12 +1338,17 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component)
|
||||
SGTL5000_INT_OSC_EN);
|
||||
/* Enable VDDC charge pump */
|
||||
ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
|
||||
} else if (vddio >= 3100 && vdda >= 3100) {
|
||||
} else {
|
||||
ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
|
||||
/* VDDC use VDDIO rail */
|
||||
lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
|
||||
lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
|
||||
SGTL5000_VDDC_MAN_ASSN_SHIFT;
|
||||
/*
|
||||
* if vddio == vdda the source of charge pump should be
|
||||
* assigned manually to VDDIO
|
||||
*/
|
||||
if (vddio == vdda) {
|
||||
lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
|
||||
lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
|
||||
SGTL5000_VDDC_MAN_ASSN_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_component_write(component, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
|
||||
@ -1288,6 +1458,7 @@ static int sgtl5000_probe(struct snd_soc_component *component)
|
||||
int ret;
|
||||
u16 reg;
|
||||
struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int zcd_mask = SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN;
|
||||
|
||||
/* power up sgtl5000 */
|
||||
ret = sgtl5000_set_power_regs(component);
|
||||
@ -1296,7 +1467,7 @@ static int sgtl5000_probe(struct snd_soc_component *component)
|
||||
|
||||
/* enable small pop, introduce 400ms delay in turning off */
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL,
|
||||
SGTL5000_SMALL_POP, 1);
|
||||
SGTL5000_SMALL_POP, SGTL5000_SMALL_POP);
|
||||
|
||||
/* disable short cut detector */
|
||||
snd_soc_component_write(component, SGTL5000_CHIP_SHORT_CTRL, 0);
|
||||
@ -1315,9 +1486,8 @@ static int sgtl5000_probe(struct snd_soc_component *component)
|
||||
0x1f);
|
||||
snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg);
|
||||
|
||||
snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL,
|
||||
SGTL5000_HP_ZCD_EN |
|
||||
SGTL5000_ADC_ZCD_EN);
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL,
|
||||
zcd_mask, zcd_mask);
|
||||
|
||||
snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
|
||||
SGTL5000_BIAS_R_MASK,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user