mirror of https://gitee.com/openkylin/linux.git
ASoC: Updates for v4.11
Another release that's mainly focused on drivers rather than core changes, highlights include: - A huge batch of updates to the Intel drivers, mainly around DisplayPort and HDMI with some additional board support too. - Channel mapping support for HDMI. - Support for AllWinner A31 and A33, Everest Semiconductor ES8328, Nuvoton NAU8540. -----BEGIN PGP SIGNATURE----- iQFHBAABCAAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlirN2kTHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0D7qB/sFOllsPc/ZNBKiB1dTSFlg//HUpupp gecc64hrQrg2wQtFG//TS+6NFt6MxzZphmyjsPWe6BGZhAq05AXtklWCdi0j8H3q KVy5gOxYM67rtGnobQ4WcTD291vkjenP7/qNxYqOgWtLfv+mMygm9FpM7S0zs18P u+Y+8cY1ljX0DaeDuMBnsNjVNyfQ+qRLhMOVT6hBVLnYHKrtcQJi1S2qC4WZV6o3 vy7Tbh+l0rf0+cbcJKBJ3qcPqS11BGt/L9QwsOeHkmTy9dzHEULRifkWcCzR7lU7 AGS5+EeCtscg29+PKDtLX4f+KHgIFHqJ/uBwoNnAdf1PMaYTUAYn/8de =x9RY -----END PGP SIGNATURE----- Merge tag 'asoc-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Updates for v4.11 Another release that's mainly focused on drivers rather than core changes, highlights include: - A huge batch of updates to the Intel drivers, mainly around DisplayPort and HDMI with some additional board support too. - Channel mapping support for HDMI. - Support for AllWinner A31 and A33, Everest Semiconductor ES8328, Nuvoton NAU8540.
This commit is contained in:
commit
4e25d30c8d
|
@ -24,6 +24,8 @@ Optional properties:
|
|||
this parameter to choose where the clock from.
|
||||
- By default the clock is from TK pin, if the clock from RK pin, this
|
||||
property is needed.
|
||||
- #sound-dai-cells: Should contain <0>.
|
||||
- This property makes the SSC into an automatically registered DAI.
|
||||
|
||||
Examples:
|
||||
- PDC transfer:
|
||||
|
|
|
@ -2,8 +2,7 @@ Devicetree bindings for the Axentia TSE-850 audio complex
|
|||
|
||||
Required properties:
|
||||
- compatible: "axentia,tse850-pcm5142"
|
||||
- axentia,ssc-controller: The phandle of the atmel SSC controller used as
|
||||
cpu dai.
|
||||
- axentia,cpu-dai: The phandle of the cpu dai.
|
||||
- axentia,audio-codec: The phandle of the PCM5142 codec.
|
||||
- axentia,add-gpios: gpio specifier that controls the mixer.
|
||||
- axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1.
|
||||
|
@ -43,6 +42,12 @@ the PCM5142 codec.
|
|||
|
||||
Example:
|
||||
|
||||
&ssc0 {
|
||||
#sound-dai-cells = <0>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c {
|
||||
codec: pcm5142@4c {
|
||||
compatible = "ti,pcm5142";
|
||||
|
@ -77,7 +82,7 @@ Example:
|
|||
sound {
|
||||
compatible = "axentia,tse850-pcm5142";
|
||||
|
||||
axentia,ssc-controller = <&ssc0>;
|
||||
axentia,cpu-dai = <&ssc0>;
|
||||
axentia,audio-codec = <&codec>;
|
||||
|
||||
axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>;
|
||||
|
|
|
@ -4,7 +4,7 @@ This device supports both I2C and SPI.
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : "everest,es8328"
|
||||
- compatible : Should be "everest,es8328" or "everest,es8388"
|
||||
- DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
|
||||
- AVDD-supply : Regulator providing analog supply voltage 3.3V
|
||||
- PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V
|
||||
|
|
|
@ -4,6 +4,7 @@ Required properties:
|
|||
- compatible = "mediatek,mt2701-audio";
|
||||
- reg: register location and size
|
||||
- interrupts: Should contain AFE interrupt
|
||||
- power-domains: should define the power domain
|
||||
- clock-names: should have these clock names:
|
||||
"infra_sys_audio_clk",
|
||||
"top_audio_mux1_sel",
|
||||
|
@ -58,6 +59,7 @@ Example:
|
|||
<0 0x112A0000 0 0x20000>;
|
||||
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
|
||||
power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
|
||||
clocks = <&infracfg CLK_INFRA_AUDIO>,
|
||||
<&topckgen CLK_TOP_AUD_MUX1_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_MUX2_SEL>,
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
NAU85L40 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "nuvoton,nau8540"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
codec: nau8540@1c {
|
||||
compatible = "nuvoton,nau8540";
|
||||
reg = <0x1c>;
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
ROCKCHIP RK3288 with HDMI and analog audio
|
||||
|
||||
Required properties:
|
||||
- compatible: "rockchip,rk3288-hdmi-analog"
|
||||
- rockchip,model: The user-visible name of this sound complex
|
||||
- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
|
||||
connected to the CODEC
|
||||
- rockchip,audio-codec: The phandle of the analog audio codec.
|
||||
- rockchip,routing: A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source. For this driver the first string should always be
|
||||
"Analog".
|
||||
|
||||
Optionnal properties:
|
||||
- rockchip,hp-en-gpios = The phandle of the GPIO that power up/down the
|
||||
headphone (when the analog output is an headphone).
|
||||
- rockchip,hp-det-gpios = The phandle of the GPIO that detects the headphone
|
||||
(when the analog output is an headphone).
|
||||
- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-es8388";
|
||||
rockchip,model = "Analog audio output";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,audio-codec = <&es8388>;
|
||||
rockchip,routing = "Analog", "LOUT2",
|
||||
"Analog", "ROUT2";
|
||||
rockchip,hp-en-gpios = <&gpio8 0 GPIO_ACTIVE_HIGH>;
|
||||
rockchip,hp-det-gpios = <&gpio7 7 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&headphone>;
|
||||
};
|
||||
|
|
@ -7,6 +7,7 @@ Required properties:
|
|||
|
||||
- compatible: should be one of the followings
|
||||
- "allwinner,sun4i-a10-i2s"
|
||||
- "allwinner,sun6i-a31-i2s"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the I2S interrupt.
|
||||
|
@ -19,6 +20,10 @@ Required properties:
|
|||
- "mod" : module clock for the I2S controller
|
||||
- #sound-dai-cells : Must be equal to 0
|
||||
|
||||
Required properties for the following compatibles:
|
||||
- "allwinner,sun6i-a31-i2s"
|
||||
- resets: phandle to the reset line for this codec
|
||||
|
||||
Example:
|
||||
|
||||
i2s0: i2s@01c22400 {
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
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@01c00000 {
|
||||
[...]
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
|
|
@ -10,6 +10,7 @@ Required properties:
|
|||
- compatible : should be one of the following:
|
||||
- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
|
||||
- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
|
||||
- "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
ZTE ZX296702 I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "zte,zx296702-i2s"
|
||||
- compatible : Must be one of:
|
||||
"zte,zx296718-i2s", "zte,zx296702-i2s"
|
||||
"zte,zx296702-i2s"
|
||||
- reg : Must contain I2S core's registers location and length
|
||||
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
|
||||
- clock-names: "tx" for the clock to the I2S interface.
|
||||
- clock-names: "wclk" for the wclk, "pclk" for the pclk to the I2S interface.
|
||||
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
|
||||
the core. The core expects two dma channels for transmit.
|
||||
- dma-names : Must be "tx" and "rx"
|
||||
|
@ -16,12 +18,12 @@ please check:
|
|||
* dma/dma.txt
|
||||
|
||||
Example:
|
||||
i2s0: i2s0@0b005000 {
|
||||
i2s0: i2s@b005000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "zte,zx296702-i2s";
|
||||
compatible = "zte,zx296718-i2s", "zte,zx296702-i2s";
|
||||
reg = <0x0b005000 0x1000>;
|
||||
clocks = <&lsp0clk ZX296702_I2S0_DIV>;
|
||||
clock-names = "tx";
|
||||
clocks = <&audiocrm AUDIO_I2S0_WCLK>, <&audiocrm AUDIO_I2S0_PCLK>;
|
||||
clock-names = "wclk", "pclk";
|
||||
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dma 5>, <&dma 6>;
|
||||
dma-names = "tx", "rx";
|
||||
|
|
|
@ -106,9 +106,7 @@ static struct s3c_audio_pdata i2sv4_pdata = {
|
|||
.dma_playback = DMACH_HSI_I2SV40_TX,
|
||||
.dma_capture = DMACH_HSI_I2SV40_RX,
|
||||
.type = {
|
||||
.i2s = {
|
||||
.quirks = QUIRK_PRI_6CHAN,
|
||||
},
|
||||
.quirks = QUIRK_PRI_6CHAN,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "../../sound/soc/atmel/atmel_ssc_dai.h"
|
||||
|
||||
/* Serialize access to ssc_list and user count */
|
||||
static DEFINE_SPINLOCK(user_lock);
|
||||
static LIST_HEAD(ssc_list);
|
||||
|
@ -145,6 +147,49 @@ static inline const struct atmel_ssc_platform_data * __init
|
|||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_ATMEL_SOC_SSC
|
||||
static int ssc_sound_dai_probe(struct ssc_device *ssc)
|
||||
{
|
||||
struct device_node *np = ssc->pdev->dev.of_node;
|
||||
int ret;
|
||||
int id;
|
||||
|
||||
ssc->sound_dai = false;
|
||||
|
||||
if (!of_property_read_bool(np, "#sound-dai-cells"))
|
||||
return 0;
|
||||
|
||||
id = of_alias_get_id(np, "ssc");
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
ret = atmel_ssc_set_audio(id);
|
||||
ssc->sound_dai = !ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssc_sound_dai_remove(struct ssc_device *ssc)
|
||||
{
|
||||
if (!ssc->sound_dai)
|
||||
return;
|
||||
|
||||
atmel_ssc_put_audio(of_alias_get_id(ssc->pdev->dev.of_node, "ssc"));
|
||||
}
|
||||
#else
|
||||
static inline int ssc_sound_dai_probe(struct ssc_device *ssc)
|
||||
{
|
||||
if (of_property_read_bool(ssc->pdev->dev.of_node, "#sound-dai-cells"))
|
||||
return -ENOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ssc_sound_dai_remove(struct ssc_device *ssc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ssc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs;
|
||||
|
@ -204,6 +249,9 @@ static int ssc_probe(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
|
||||
ssc->regs, ssc->irq);
|
||||
|
||||
if (ssc_sound_dai_probe(ssc))
|
||||
dev_err(&pdev->dev, "failed to auto-setup ssc for audio\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -211,6 +259,8 @@ static int ssc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ssc_device *ssc = platform_get_drvdata(pdev);
|
||||
|
||||
ssc_sound_dai_remove(ssc);
|
||||
|
||||
spin_lock(&user_lock);
|
||||
list_del(&ssc->list);
|
||||
spin_unlock(&user_lock);
|
||||
|
|
|
@ -248,6 +248,7 @@ struct detailed_timing {
|
|||
# define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */
|
||||
|
||||
#define DRM_ELD_SPEAKER 7
|
||||
# define DRM_ELD_SPEAKER_MASK 0x7f
|
||||
# define DRM_ELD_SPEAKER_RLRC (1 << 6)
|
||||
# define DRM_ELD_SPEAKER_FLRC (1 << 5)
|
||||
# define DRM_ELD_SPEAKER_RC (1 << 4)
|
||||
|
@ -413,6 +414,18 @@ static inline int drm_eld_size(const uint8_t *eld)
|
|||
return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_eld_get_spk_alloc - Get speaker allocation
|
||||
* @eld: pointer to an ELD memory structure
|
||||
*
|
||||
* The returned value is the speakers mask. User has to use %DRM_ELD_SPEAKER
|
||||
* field definitions to identify speakers.
|
||||
*/
|
||||
static inline u8 drm_eld_get_spk_alloc(const uint8_t *eld)
|
||||
{
|
||||
return eld[DRM_ELD_SPEAKER] & DRM_ELD_SPEAKER_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_eld_get_conn_type - Get device type hdmi/dp connected
|
||||
* @eld: pointer to an ELD memory structure
|
||||
|
|
|
@ -20,6 +20,7 @@ struct ssc_device {
|
|||
int user;
|
||||
int irq;
|
||||
bool clk_from_rk_pin;
|
||||
bool sound_dai;
|
||||
};
|
||||
|
||||
struct ssc_device * __must_check ssc_request(unsigned int ssc_num);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
extern void s3c64xx_ac97_setup_gpio(int);
|
||||
|
||||
struct samsung_i2s {
|
||||
struct samsung_i2s_type {
|
||||
/* If the Primary DAI has 5.1 Channels */
|
||||
#define QUIRK_PRI_6CHAN (1 << 0)
|
||||
/* If the I2S block has a Stereo Overlay Channel */
|
||||
|
@ -47,7 +47,5 @@ struct s3c_audio_pdata {
|
|||
void *dma_capture;
|
||||
void *dma_play_sec;
|
||||
void *dma_capture_mic;
|
||||
union {
|
||||
struct samsung_i2s i2s;
|
||||
} type;
|
||||
struct samsung_i2s_type type;
|
||||
};
|
||||
|
|
|
@ -71,6 +71,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
|
|||
* @slave_id: Slave requester id for the DMA channel.
|
||||
* @filter_data: Custom DMA channel filter data, this will usually be used when
|
||||
* requesting the DMA channel.
|
||||
* @chan_name: Custom channel name to use when requesting DMA channel.
|
||||
* @fifo_size: FIFO size of the DAI controller in bytes
|
||||
* @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
|
||||
*/
|
||||
|
@ -80,6 +81,7 @@ struct snd_dmaengine_dai_dma_data {
|
|||
u32 maxburst;
|
||||
unsigned int slave_id;
|
||||
void *filter_data;
|
||||
const char *chan_name;
|
||||
unsigned int fifo_size;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
@ -105,6 +107,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
|
|||
* playback.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3)
|
||||
/*
|
||||
* The PCM streams have custom channel names specified.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4)
|
||||
|
||||
/**
|
||||
* struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
|
||||
|
|
|
@ -34,11 +34,12 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
|
|||
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
||||
char *prefix);
|
||||
|
||||
#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(node, dai_link->cpu_of_node, simple_dai)
|
||||
#define asoc_simple_card_parse_clk_codec(node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(node, dai_link->codec_of_node, simple_dai)
|
||||
int asoc_simple_card_parse_clk(struct device_node *node,
|
||||
#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai)
|
||||
#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
|
||||
asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai)
|
||||
int asoc_simple_card_parse_clk(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct device_node *dai_of_node,
|
||||
struct asoc_simple_dai *simple_dai);
|
||||
|
||||
|
|
|
@ -256,6 +256,9 @@ struct snd_soc_dai_driver {
|
|||
int (*resume)(struct snd_soc_dai *dai);
|
||||
/* compress dai */
|
||||
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
|
||||
/* 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;
|
||||
|
||||
|
|
|
@ -497,6 +497,8 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
|
|||
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
|
||||
unsigned int dai_fmt);
|
||||
|
||||
int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
|
||||
|
@ -507,9 +509,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 snd_soc_platform_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_platform *platform);
|
||||
|
||||
int soc_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
|
@ -785,6 +784,10 @@ struct snd_soc_component_driver {
|
|||
int (*suspend)(struct snd_soc_component *);
|
||||
int (*resume)(struct snd_soc_component *);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* DT */
|
||||
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
|
@ -859,6 +862,8 @@ struct snd_soc_component {
|
|||
void (*remove)(struct snd_soc_component *);
|
||||
int (*suspend)(struct snd_soc_component *);
|
||||
int (*resume)(struct snd_soc_component *);
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* machine specific init */
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
|
@ -941,20 +946,11 @@ struct snd_soc_platform_driver {
|
|||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/*
|
||||
* For platform caused delay reporting.
|
||||
* Optional.
|
||||
*/
|
||||
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
|
||||
struct snd_soc_dai *);
|
||||
|
||||
/* platform stream pcm ops */
|
||||
const struct snd_pcm_ops *ops;
|
||||
|
||||
/* platform stream compress ops */
|
||||
const struct snd_compr_ops *compr_ops;
|
||||
|
||||
int (*bespoke_trigger)(struct snd_pcm_substream *, int);
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link_component {
|
||||
|
@ -1099,6 +1095,8 @@ struct snd_soc_card {
|
|||
const char *name;
|
||||
const char *long_name;
|
||||
const char *driver_name;
|
||||
char dmi_longname[80];
|
||||
|
||||
struct device *dev;
|
||||
struct snd_card *snd_card;
|
||||
struct module *owner;
|
||||
|
@ -1647,37 +1645,21 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
|
|||
int snd_soc_util_init(void);
|
||||
void snd_soc_util_exit(void);
|
||||
|
||||
#define snd_soc_of_parse_card_name(card, propname) \
|
||||
snd_soc_of_parse_card_name_from_node(card, NULL, propname)
|
||||
int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
|
||||
struct device_node *np,
|
||||
const char *propname);
|
||||
#define snd_soc_of_parse_audio_simple_widgets(card, propname)\
|
||||
snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname)
|
||||
int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
|
||||
struct device_node *np,
|
||||
const char *propname);
|
||||
|
||||
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
|
||||
const char *propname);
|
||||
int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
|
||||
const char *propname);
|
||||
int snd_soc_of_parse_tdm_slot(struct device_node *np,
|
||||
unsigned int *tx_mask,
|
||||
unsigned int *rx_mask,
|
||||
unsigned int *slots,
|
||||
unsigned int *slot_width);
|
||||
#define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \
|
||||
snd_soc_of_parse_audio_prefix_from_node(card, NULL, codec_conf, \
|
||||
of_node, propname)
|
||||
void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card,
|
||||
struct device_node *np,
|
||||
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
|
||||
struct snd_soc_codec_conf *codec_conf,
|
||||
struct device_node *of_node,
|
||||
const char *propname);
|
||||
|
||||
#define snd_soc_of_parse_audio_routing(card, propname) \
|
||||
snd_soc_of_parse_audio_routing_from_node(card, NULL, propname)
|
||||
int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card,
|
||||
struct device_node *np,
|
||||
const char *propname);
|
||||
|
||||
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
||||
const char *propname);
|
||||
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
||||
const char *prefix,
|
||||
struct device_node **bitclkmaster,
|
||||
|
|
|
@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
|
|||
{
|
||||
struct hdac_stream *hstream = &stream->hstream;
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
u32 val;
|
||||
int mask = AZX_PPCTL_PROCEN(hstream->index);
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
if (decouple)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
|
||||
AZX_PPCTL_PROCEN(hstream->index));
|
||||
else
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
|
||||
AZX_PPCTL_PROCEN(hstream->index), 0);
|
||||
val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
|
||||
|
||||
if (decouple && !val)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
|
||||
else if (!decouple && val)
|
||||
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
|
||||
|
||||
stream->decoupled = decouple;
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
|
|
|
@ -670,13 +670,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
int status;
|
||||
uint64_t size;
|
||||
struct snd_dma_buffer *dma_buffer;
|
||||
struct page *pg;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct audio_substream_data *rtd;
|
||||
|
||||
dma_buffer = &substream->dma_buffer;
|
||||
|
||||
runtime = substream->runtime;
|
||||
rtd = runtime->private_data;
|
||||
|
||||
|
|
|
@ -51,11 +51,7 @@
|
|||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
struct tse850_priv {
|
||||
int ssc_id;
|
||||
|
||||
struct gpio_desc *add;
|
||||
struct gpio_desc *loop1;
|
||||
struct gpio_desc *loop2;
|
||||
|
@ -329,23 +325,20 @@ static int tse850_dt_init(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct snd_soc_card *card = &tse850_card;
|
||||
struct snd_soc_dai_link *dailink = &tse850_dailink;
|
||||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "only device tree supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0);
|
||||
cpu_np = of_parse_phandle(np, "axentia,cpu-dai", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "failed to get dai and pcm info\n");
|
||||
dev_err(&pdev->dev, "failed to get cpu dai\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dailink->cpu_of_node = cpu_np;
|
||||
dailink->platform_of_node = cpu_np;
|
||||
tse850->ssc_id = of_alias_get_id(cpu_np, "ssc");
|
||||
of_node_put(cpu_np);
|
||||
|
||||
codec_np = of_parse_phandle(np, "axentia,audio-codec", 0);
|
||||
|
@ -415,23 +408,14 @@ static int tse850_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = atmel_ssc_set_audio(tse850->ssc_id);
|
||||
if (ret != 0) {
|
||||
dev_err(dev,
|
||||
"failed to set SSC %d for audio\n", tse850->ssc_id);
|
||||
goto err_disable_ana;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(dev, "snd_soc_register_card failed\n");
|
||||
goto err_put_audio;
|
||||
goto err_disable_ana;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_audio:
|
||||
atmel_ssc_put_audio(tse850->ssc_id);
|
||||
err_disable_ana:
|
||||
regulator_disable(tse850->ana);
|
||||
return ret;
|
||||
|
@ -443,7 +427,6 @@ static int tse850_remove(struct platform_device *pdev)
|
|||
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
atmel_ssc_put_audio(tse850->ssc_id);
|
||||
regulator_disable(tse850->ana);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -45,7 +45,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_ALC5623 if I2C
|
||||
select SND_SOC_ALC5632 if I2C
|
||||
select SND_SOC_BT_SCO
|
||||
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
|
||||
select SND_SOC_CQ0093VC
|
||||
select SND_SOC_CS35L32 if I2C
|
||||
select SND_SOC_CS35L33 if I2C
|
||||
select SND_SOC_CS35L34 if I2C
|
||||
|
@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_MAX9877 if I2C
|
||||
select SND_SOC_MC13783 if MFD_MC13XXX
|
||||
select SND_SOC_ML26124 if I2C
|
||||
select SND_SOC_NAU8540 if I2C
|
||||
select SND_SOC_NAU8810 if I2C
|
||||
select SND_SOC_NAU8825 if I2C
|
||||
select SND_SOC_HDMI_CODEC
|
||||
|
@ -117,8 +118,8 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_RT5651 if I2C
|
||||
select SND_SOC_RT5659 if I2C
|
||||
select SND_SOC_RT5660 if I2C
|
||||
select SND_SOC_RT5665 if I2C
|
||||
select SND_SOC_RT5663 if I2C
|
||||
select SND_SOC_RT5665 if I2C
|
||||
select SND_SOC_RT5670 if I2C
|
||||
select SND_SOC_RT5677 if I2C && SPI_MASTER
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
|
@ -525,14 +526,16 @@ config SND_SOC_HDMI_CODEC
|
|||
select HDMI
|
||||
|
||||
config SND_SOC_ES8328
|
||||
tristate "Everest Semi ES8328 CODEC"
|
||||
tristate
|
||||
|
||||
config SND_SOC_ES8328_I2C
|
||||
tristate
|
||||
tristate "Everest Semi ES8328 CODEC (I2C)"
|
||||
depends on I2C
|
||||
select SND_SOC_ES8328
|
||||
|
||||
config SND_SOC_ES8328_SPI
|
||||
tristate
|
||||
tristate "Everest Semi ES8328 CODEC (SPI)"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_ES8328
|
||||
|
||||
config SND_SOC_GTM601
|
||||
|
@ -668,8 +671,8 @@ config SND_SOC_RL6231
|
|||
default y if SND_SOC_RT5651=y
|
||||
default y if SND_SOC_RT5659=y
|
||||
default y if SND_SOC_RT5660=y
|
||||
default y if SND_SOC_RT5665=y
|
||||
default y if SND_SOC_RT5663=y
|
||||
default y if SND_SOC_RT5665=y
|
||||
default y if SND_SOC_RT5670=y
|
||||
default y if SND_SOC_RT5677=y
|
||||
default m if SND_SOC_RT5514=m
|
||||
|
@ -679,8 +682,8 @@ config SND_SOC_RL6231
|
|||
default m if SND_SOC_RT5651=m
|
||||
default m if SND_SOC_RT5659=m
|
||||
default m if SND_SOC_RT5660=m
|
||||
default m if SND_SOC_RT5665=m
|
||||
default m if SND_SOC_RT5663=m
|
||||
default m if SND_SOC_RT5665=m
|
||||
default m if SND_SOC_RT5670=m
|
||||
default m if SND_SOC_RT5677=m
|
||||
|
||||
|
@ -728,10 +731,10 @@ config SND_SOC_RT5659
|
|||
config SND_SOC_RT5660
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5665
|
||||
config SND_SOC_RT5663
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5663
|
||||
config SND_SOC_RT5665
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5670
|
||||
|
@ -1105,6 +1108,10 @@ config SND_SOC_MC13783
|
|||
config SND_SOC_ML26124
|
||||
tristate
|
||||
|
||||
config SND_SOC_NAU8540
|
||||
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_NAU8810
|
||||
tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
|
||||
depends on I2C
|
||||
|
|
|
@ -90,6 +90,7 @@ snd-soc-mc13783-objs := mc13783.o
|
|||
snd-soc-ml26124-objs := ml26124.o
|
||||
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
|
||||
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
|
||||
snd-soc-nau8540-objs := nau8540.o
|
||||
snd-soc-nau8810-objs := nau8810.o
|
||||
snd-soc-nau8825-objs := nau8825.o
|
||||
snd-soc-hdmi-codec-objs := hdmi-codec.o
|
||||
|
@ -118,8 +119,8 @@ snd-soc-rt5645-objs := rt5645.o
|
|||
snd-soc-rt5651-objs := rt5651.o
|
||||
snd-soc-rt5659-objs := rt5659.o
|
||||
snd-soc-rt5660-objs := rt5660.o
|
||||
snd-soc-rt5665-objs := rt5665.o
|
||||
snd-soc-rt5663-objs := rt5663.o
|
||||
snd-soc-rt5665-objs := rt5665.o
|
||||
snd-soc-rt5670-objs := rt5670.o
|
||||
snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-rt5677-spi-objs := rt5677-spi.o
|
||||
|
@ -318,6 +319,7 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
|
|||
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
|
||||
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
|
||||
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
|
||||
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
|
||||
|
@ -346,8 +348,8 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
|
|||
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
|
||||
obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
|
||||
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o
|
||||
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
|
||||
obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o
|
||||
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
|
||||
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
|
||||
|
|
|
@ -65,7 +65,6 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
|||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
adau->pll_regs[5] = 1;
|
||||
|
@ -78,7 +77,7 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
|||
}
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
|
|
|
@ -189,7 +189,7 @@ static int ak4642_lout_event(struct snd_soc_dapm_widget *w,
|
|||
case SND_SOC_DAPM_POST_PMU:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* Power save mode OFF */
|
||||
mdelay(300);
|
||||
msleep(300);
|
||||
snd_soc_update_bits(codec, SG_SL2, LOPS, 0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -192,6 +192,7 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
|
|||
#define ARIZONA_DSP_ROUTES(name) \
|
||||
{ name, NULL, name " Preloader"}, \
|
||||
{ name " Preloader", NULL, "SYSCLK" }, \
|
||||
{ name " Preload", NULL, name " Preloader"}, \
|
||||
{ name, NULL, name " Aux 1" }, \
|
||||
{ name, NULL, name " Aux 2" }, \
|
||||
{ name, NULL, name " Aux 3" }, \
|
||||
|
|
|
@ -173,6 +173,9 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
|
|||
SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
|
||||
SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
|
||||
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
|
||||
|
@ -1121,7 +1124,10 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
|
|||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
|
|
@ -1634,7 +1634,8 @@ static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/* DAI */
|
||||
SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7218_DAI_TDM_CTRL,
|
||||
DA7218_DAI_OE_SHIFT, DA7218_NO_INVERT),
|
||||
SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
/* Output Mixers */
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
|
||||
static const struct i2c_device_id es8328_id[] = {
|
||||
{ "es8328", 0 },
|
||||
{ "es8388", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, es8328_id);
|
||||
|
||||
static const struct of_device_id es8328_of_match[] = {
|
||||
{ .compatible = "everest,es8328", },
|
||||
{ .compatible = "everest,es8388", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, es8328_of_match);
|
||||
|
|
|
@ -589,9 +589,21 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
u8 dac_mode = 0;
|
||||
u8 adc_mode = 0;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* Master serial port mode, with BCLK generated automatically */
|
||||
snd_soc_update_bits(codec, ES8328_MASTERMODE,
|
||||
ES8328_MASTERMODE_MSC,
|
||||
ES8328_MASTERMODE_MSC);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
/* Slave serial port mode */
|
||||
snd_soc_update_bits(codec, ES8328_MASTERMODE,
|
||||
ES8328_MASTERMODE_MSC, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
@ -620,10 +632,6 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
|
||||
ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode);
|
||||
|
||||
/* Master serial port mode, with BCLK generated automatically */
|
||||
snd_soc_update_bits(codec, ES8328_MASTERMODE,
|
||||
ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,9 @@
|
|||
#ifndef __HDAC_HDMI_H__
|
||||
#define __HDAC_HDMI_H__
|
||||
|
||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm);
|
||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
|
||||
struct snd_soc_jack *jack);
|
||||
|
||||
int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dapm_context *dapm);
|
||||
#endif /* __HDAC_HDMI_H__ */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
#include <sound/hdmi-codec.h>
|
||||
#include <sound/pcm_iec958.h>
|
||||
|
@ -31,8 +32,261 @@ struct hdmi_device {
|
|||
};
|
||||
#define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list)
|
||||
LIST_HEAD(hdmi_device_list);
|
||||
static DEFINE_MUTEX(hdmi_mutex);
|
||||
|
||||
#define DAI_NAME_SIZE 16
|
||||
|
||||
#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
|
||||
|
||||
struct hdmi_codec_channel_map_table {
|
||||
unsigned char map; /* ALSA API channel map position */
|
||||
unsigned long spk_mask; /* speaker position bit mask */
|
||||
};
|
||||
|
||||
/*
|
||||
* CEA speaker placement for HDMI 1.4:
|
||||
*
|
||||
* FL FLC FC FRC FR FRW
|
||||
*
|
||||
* LFE
|
||||
*
|
||||
* RL RLC RC RRC RR
|
||||
*
|
||||
* Speaker placement has to be extended to support HDMI 2.0
|
||||
*/
|
||||
enum hdmi_codec_cea_spk_placement {
|
||||
FL = BIT(0), /* Front Left */
|
||||
FC = BIT(1), /* Front Center */
|
||||
FR = BIT(2), /* Front Right */
|
||||
FLC = BIT(3), /* Front Left Center */
|
||||
FRC = BIT(4), /* Front Right Center */
|
||||
RL = BIT(5), /* Rear Left */
|
||||
RC = BIT(6), /* Rear Center */
|
||||
RR = BIT(7), /* Rear Right */
|
||||
RLC = BIT(8), /* Rear Left Center */
|
||||
RRC = BIT(9), /* Rear Right Center */
|
||||
LFE = BIT(10), /* Low Frequency Effect */
|
||||
};
|
||||
|
||||
/*
|
||||
* cea Speaker allocation structure
|
||||
*/
|
||||
struct hdmi_codec_cea_spk_alloc {
|
||||
const int ca_id;
|
||||
unsigned int n_ch;
|
||||
unsigned long mask;
|
||||
};
|
||||
|
||||
/* Channel maps stereo HDMI */
|
||||
const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
|
||||
{ .channels = 2,
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Channel maps for multi-channel playbacks, up to 8 n_ch */
|
||||
const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
|
||||
{ .channels = 2, /* CA_ID 0x00 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
|
||||
{ .channels = 4, /* CA_ID 0x01 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA } },
|
||||
{ .channels = 4, /* CA_ID 0x02 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC } },
|
||||
{ .channels = 4, /* CA_ID 0x03 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC } },
|
||||
{ .channels = 6, /* CA_ID 0x04 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 6, /* CA_ID 0x05 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 6, /* CA_ID 0x06 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 6, /* CA_ID 0x07 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 6, /* CA_ID 0x08 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
|
||||
{ .channels = 6, /* CA_ID 0x09 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
|
||||
{ .channels = 6, /* CA_ID 0x0A */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
|
||||
{ .channels = 6, /* CA_ID 0x0B */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
|
||||
{ .channels = 8, /* CA_ID 0x0C */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 8, /* CA_ID 0x0D */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 8, /* CA_ID 0x0E */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 8, /* CA_ID 0x0F */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
|
||||
{ .channels = 8, /* CA_ID 0x10 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
|
||||
{ .channels = 8, /* CA_ID 0x11 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
|
||||
{ .channels = 8, /* CA_ID 0x12 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
|
||||
{ .channels = 8, /* CA_ID 0x13 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
|
||||
SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
|
||||
{ .channels = 8, /* CA_ID 0x14 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x15 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x16 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x17 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x18 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x19 */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1A */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1B */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1C */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1D */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1E */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ .channels = 8, /* CA_ID 0x1F */
|
||||
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
|
||||
SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
|
||||
SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* hdmi_codec_channel_alloc: speaker configuration available for CEA
|
||||
*
|
||||
* This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
|
||||
* The preceding ones have better chances to be selected by
|
||||
* hdmi_codec_get_ch_alloc_table_idx().
|
||||
*/
|
||||
static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
|
||||
{ .ca_id = 0x00, .n_ch = 2,
|
||||
.mask = FL | FR},
|
||||
/* 2.1 */
|
||||
{ .ca_id = 0x01, .n_ch = 4,
|
||||
.mask = FL | FR | LFE},
|
||||
/* Dolby Surround */
|
||||
{ .ca_id = 0x02, .n_ch = 4,
|
||||
.mask = FL | FR | FC },
|
||||
/* surround51 */
|
||||
{ .ca_id = 0x0b, .n_ch = 6,
|
||||
.mask = FL | FR | LFE | FC | RL | RR},
|
||||
/* surround40 */
|
||||
{ .ca_id = 0x08, .n_ch = 6,
|
||||
.mask = FL | FR | RL | RR },
|
||||
/* surround41 */
|
||||
{ .ca_id = 0x09, .n_ch = 6,
|
||||
.mask = FL | FR | LFE | RL | RR },
|
||||
/* surround50 */
|
||||
{ .ca_id = 0x0a, .n_ch = 6,
|
||||
.mask = FL | FR | FC | RL | RR },
|
||||
/* 6.1 */
|
||||
{ .ca_id = 0x0f, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | RL | RR | RC },
|
||||
/* surround71 */
|
||||
{ .ca_id = 0x13, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
|
||||
/* others */
|
||||
{ .ca_id = 0x03, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC },
|
||||
{ .ca_id = 0x04, .n_ch = 8,
|
||||
.mask = FL | FR | RC},
|
||||
{ .ca_id = 0x05, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RC },
|
||||
{ .ca_id = 0x06, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RC },
|
||||
{ .ca_id = 0x07, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | RC },
|
||||
{ .ca_id = 0x0c, .n_ch = 8,
|
||||
.mask = FL | FR | RC | RL | RR },
|
||||
{ .ca_id = 0x0d, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RL | RR | RC },
|
||||
{ .ca_id = 0x0e, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RL | RR | RC },
|
||||
{ .ca_id = 0x10, .n_ch = 8,
|
||||
.mask = FL | FR | RL | RR | RLC | RRC },
|
||||
{ .ca_id = 0x11, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RL | RR | RLC | RRC },
|
||||
{ .ca_id = 0x12, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RL | RR | RLC | RRC },
|
||||
{ .ca_id = 0x14, .n_ch = 8,
|
||||
.mask = FL | FR | FLC | FRC },
|
||||
{ .ca_id = 0x15, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FLC | FRC },
|
||||
{ .ca_id = 0x16, .n_ch = 8,
|
||||
.mask = FL | FR | FC | FLC | FRC },
|
||||
{ .ca_id = 0x17, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | FLC | FRC },
|
||||
{ .ca_id = 0x18, .n_ch = 8,
|
||||
.mask = FL | FR | RC | FLC | FRC },
|
||||
{ .ca_id = 0x19, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RC | FLC | FRC },
|
||||
{ .ca_id = 0x1a, .n_ch = 8,
|
||||
.mask = FL | FR | RC | FC | FLC | FRC },
|
||||
{ .ca_id = 0x1b, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RC | FC | FLC | FRC },
|
||||
{ .ca_id = 0x1c, .n_ch = 8,
|
||||
.mask = FL | FR | RL | RR | FLC | FRC },
|
||||
{ .ca_id = 0x1d, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | RL | RR | FLC | FRC },
|
||||
{ .ca_id = 0x1e, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RL | RR | FLC | FRC },
|
||||
{ .ca_id = 0x1f, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
|
||||
};
|
||||
|
||||
struct hdmi_codec_priv {
|
||||
struct hdmi_codec_pdata hcd;
|
||||
struct snd_soc_dai_driver *daidrv;
|
||||
|
@ -41,6 +295,8 @@ struct hdmi_codec_priv {
|
|||
struct snd_pcm_substream *current_stream;
|
||||
struct snd_pcm_hw_constraint_list ratec;
|
||||
uint8_t eld[MAX_ELD_BYTES];
|
||||
struct snd_pcm_chmap *chmap_info;
|
||||
unsigned int chmap_idx;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget hdmi_widgets[] = {
|
||||
|
@ -79,6 +335,83 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
|
||||
{
|
||||
int i;
|
||||
const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
|
||||
[0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
|
||||
[4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
|
||||
};
|
||||
unsigned long spk_mask = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) {
|
||||
if (spk_alloc & (1 << i))
|
||||
spk_mask |= hdmi_codec_eld_spk_alloc_bits[i];
|
||||
}
|
||||
|
||||
return spk_mask;
|
||||
}
|
||||
|
||||
void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
|
||||
{
|
||||
u8 spk_alloc;
|
||||
unsigned long spk_mask;
|
||||
|
||||
spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
|
||||
spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
|
||||
|
||||
/* Detect if only stereo supported, else return 8 channels mappings */
|
||||
if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2)
|
||||
hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps;
|
||||
else
|
||||
hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
|
||||
}
|
||||
|
||||
static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp,
|
||||
unsigned char channels)
|
||||
{
|
||||
int i;
|
||||
u8 spk_alloc;
|
||||
unsigned long spk_mask;
|
||||
const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc;
|
||||
|
||||
spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
|
||||
spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) {
|
||||
/* If spk_alloc == 0, HDMI is unplugged return stereo config*/
|
||||
if (!spk_alloc && cap->ca_id == 0)
|
||||
return i;
|
||||
if (cap->n_ch != channels)
|
||||
continue;
|
||||
if (!(cap->mask == (spk_mask & cap->mask)))
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
unsigned const char *map;
|
||||
unsigned int i;
|
||||
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
|
||||
struct hdmi_codec_priv *hcp = info->private_data;
|
||||
|
||||
map = info->chmap[hcp->chmap_idx].map;
|
||||
|
||||
for (i = 0; i < info->max_channels; i++) {
|
||||
if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
|
||||
ucontrol->value.integer.value[i] = 0;
|
||||
else
|
||||
ucontrol->value.integer.value[i] = map[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_kcontrol_new hdmi_controls[] = {
|
||||
{
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
|
@ -140,6 +473,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* Select chmap supported */
|
||||
hdmi_codec_eld_chmap(hcp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,6 +488,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
|
|||
|
||||
WARN_ON(hcp->current_stream != substream);
|
||||
|
||||
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
|
||||
|
||||
mutex_lock(&hcp->current_stream_lock);
|
||||
|
@ -173,7 +509,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
.dig_subframe = { 0 },
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
int ret, idx;
|
||||
|
||||
dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
|
||||
params_width(params), params_rate(params),
|
||||
|
@ -200,6 +536,17 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
|
||||
hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
|
||||
|
||||
/* Select a channel allocation that matches with ELD and pcm channels */
|
||||
idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels);
|
||||
if (idx < 0) {
|
||||
dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
idx);
|
||||
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
return idx;
|
||||
}
|
||||
hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
|
||||
hp.sample_width = params_width(params);
|
||||
hp.sample_rate = params_rate(params);
|
||||
hp.channels = params_channels(params);
|
||||
|
@ -328,6 +675,32 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
|
|||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
|
||||
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
|
||||
|
||||
static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_dai_driver *drv = dai->driver;
|
||||
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dai->dev, "%s()\n", __func__);
|
||||
|
||||
ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
NULL, drv->playback.channels_max, 0,
|
||||
&hcp->chmap_info);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* override handlers */
|
||||
hcp->chmap_info->private_data = hcp;
|
||||
hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get;
|
||||
|
||||
/* default chmap supported is stereo */
|
||||
hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
|
||||
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver hdmi_i2s_dai = {
|
||||
.id = DAI_ID_I2S,
|
||||
.playback = {
|
||||
|
@ -339,6 +712,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
|
|||
.sig_bits = 24,
|
||||
},
|
||||
.ops = &hdmi_dai_ops,
|
||||
.pcm_new = hdmi_codec_pcm_new,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_driver hdmi_spdif_dai = {
|
||||
|
@ -351,6 +725,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
|
|||
.formats = SPDIF_FORMATS,
|
||||
},
|
||||
.ops = &hdmi_dai_ops,
|
||||
.pcm_new = hdmi_codec_pcm_new,
|
||||
};
|
||||
|
||||
static char hdmi_dai_name[][DAI_NAME_SIZE] = {
|
||||
|
@ -420,6 +795,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
hd = NULL;
|
||||
mutex_lock(&hdmi_mutex);
|
||||
list_for_each(pos, &hdmi_device_list) {
|
||||
struct hdmi_device *tmp = pos_to_hdmi_device(pos);
|
||||
|
||||
|
@ -431,13 +807,16 @@ static int hdmi_codec_probe(struct platform_device *pdev)
|
|||
|
||||
if (!hd) {
|
||||
hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
|
||||
if (!hd)
|
||||
if (!hd) {
|
||||
mutex_unlock(&hdmi_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hd->dev = dev->parent;
|
||||
|
||||
list_add_tail(&hd->list, &hdmi_device_list);
|
||||
}
|
||||
mutex_unlock(&hdmi_mutex);
|
||||
|
||||
if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
|
||||
dev_err(dev, "too many hdmi codec are deteced\n");
|
||||
|
@ -479,7 +858,25 @@ static int hdmi_codec_probe(struct platform_device *pdev)
|
|||
|
||||
static int hdmi_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct list_head *pos;
|
||||
struct hdmi_codec_priv *hcp;
|
||||
|
||||
mutex_lock(&hdmi_mutex);
|
||||
list_for_each(pos, &hdmi_device_list) {
|
||||
struct hdmi_device *tmp = pos_to_hdmi_device(pos);
|
||||
|
||||
if (tmp->dev == dev->parent) {
|
||||
list_del(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&hdmi_mutex);
|
||||
|
||||
hcp = dev_get_drvdata(dev);
|
||||
kfree(hcp->chmap_info);
|
||||
snd_soc_unregister_codec(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2456,7 +2456,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
|
|||
if (err) {
|
||||
micbias = M98090_MBVSEL_2V8;
|
||||
dev_info(codec->dev, "use default 2.8v micbias\n");
|
||||
} else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) {
|
||||
} else if (micbias > M98090_MBVSEL_2V8) {
|
||||
dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
|
||||
micbias = M98090_MBVSEL_2V8;
|
||||
}
|
||||
|
|
|
@ -309,7 +309,6 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
|
|||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 iface1A = 0, iface1B = 0;
|
||||
int ret;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
|
@ -346,8 +345,8 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
|
||||
ret = regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
|
||||
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
|
||||
regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,835 @@
|
|||
/*
|
||||
* NAU85L40 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2016 Nuvoton Technology Corp.
|
||||
* Author: John Hsu <KCHSU0@nuvoton.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "nau8540.h"
|
||||
|
||||
|
||||
#define NAU_FREF_MAX 13500000
|
||||
#define NAU_FVCO_MAX 100000000
|
||||
#define NAU_FVCO_MIN 90000000
|
||||
|
||||
/* the maximum frequency of CLK_ADC */
|
||||
#define CLK_ADC_MAX 6144000
|
||||
|
||||
/* scaling for mclk from sysclk_src output */
|
||||
static const struct nau8540_fll_attr mclk_src_scaling[] = {
|
||||
{ 1, 0x0 },
|
||||
{ 2, 0x2 },
|
||||
{ 4, 0x3 },
|
||||
{ 8, 0x4 },
|
||||
{ 16, 0x5 },
|
||||
{ 32, 0x6 },
|
||||
{ 3, 0x7 },
|
||||
{ 6, 0xa },
|
||||
{ 12, 0xb },
|
||||
{ 24, 0xc },
|
||||
};
|
||||
|
||||
/* ratio for input clk freq */
|
||||
static const struct nau8540_fll_attr fll_ratio[] = {
|
||||
{ 512000, 0x01 },
|
||||
{ 256000, 0x02 },
|
||||
{ 128000, 0x04 },
|
||||
{ 64000, 0x08 },
|
||||
{ 32000, 0x10 },
|
||||
{ 8000, 0x20 },
|
||||
{ 4000, 0x40 },
|
||||
};
|
||||
|
||||
static const struct nau8540_fll_attr fll_pre_scalar[] = {
|
||||
{ 1, 0x0 },
|
||||
{ 2, 0x1 },
|
||||
{ 4, 0x2 },
|
||||
{ 8, 0x3 },
|
||||
};
|
||||
|
||||
/* over sampling rate */
|
||||
static const struct nau8540_osr_attr osr_adc_sel[] = {
|
||||
{ 32, 3 }, /* OSR 32, SRC 1/8 */
|
||||
{ 64, 2 }, /* OSR 64, SRC 1/4 */
|
||||
{ 128, 1 }, /* OSR 128, SRC 1/2 */
|
||||
{ 256, 0 }, /* OSR 256, SRC 1 */
|
||||
};
|
||||
|
||||
static const struct reg_default nau8540_reg_defaults[] = {
|
||||
{NAU8540_REG_POWER_MANAGEMENT, 0x0000},
|
||||
{NAU8540_REG_CLOCK_CTRL, 0x0000},
|
||||
{NAU8540_REG_CLOCK_SRC, 0x0000},
|
||||
{NAU8540_REG_FLL1, 0x0001},
|
||||
{NAU8540_REG_FLL2, 0x3126},
|
||||
{NAU8540_REG_FLL3, 0x0008},
|
||||
{NAU8540_REG_FLL4, 0x0010},
|
||||
{NAU8540_REG_FLL5, 0xC000},
|
||||
{NAU8540_REG_FLL6, 0x6000},
|
||||
{NAU8540_REG_FLL_VCO_RSV, 0xF13C},
|
||||
{NAU8540_REG_PCM_CTRL0, 0x000B},
|
||||
{NAU8540_REG_PCM_CTRL1, 0x3010},
|
||||
{NAU8540_REG_PCM_CTRL2, 0x0800},
|
||||
{NAU8540_REG_PCM_CTRL3, 0x0000},
|
||||
{NAU8540_REG_PCM_CTRL4, 0x000F},
|
||||
{NAU8540_REG_ALC_CONTROL_1, 0x0000},
|
||||
{NAU8540_REG_ALC_CONTROL_2, 0x700B},
|
||||
{NAU8540_REG_ALC_CONTROL_3, 0x0022},
|
||||
{NAU8540_REG_ALC_CONTROL_4, 0x1010},
|
||||
{NAU8540_REG_ALC_CONTROL_5, 0x1010},
|
||||
{NAU8540_REG_NOTCH_FIL1_CH1, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL2_CH1, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL1_CH2, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL2_CH2, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL1_CH3, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL2_CH3, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL1_CH4, 0x0000},
|
||||
{NAU8540_REG_NOTCH_FIL2_CH4, 0x0000},
|
||||
{NAU8540_REG_HPF_FILTER_CH12, 0x0000},
|
||||
{NAU8540_REG_HPF_FILTER_CH34, 0x0000},
|
||||
{NAU8540_REG_ADC_SAMPLE_RATE, 0x0002},
|
||||
{NAU8540_REG_DIGITAL_GAIN_CH1, 0x0400},
|
||||
{NAU8540_REG_DIGITAL_GAIN_CH2, 0x0400},
|
||||
{NAU8540_REG_DIGITAL_GAIN_CH3, 0x0400},
|
||||
{NAU8540_REG_DIGITAL_GAIN_CH4, 0x0400},
|
||||
{NAU8540_REG_DIGITAL_MUX, 0x00E4},
|
||||
{NAU8540_REG_GPIO_CTRL, 0x0000},
|
||||
{NAU8540_REG_MISC_CTRL, 0x0000},
|
||||
{NAU8540_REG_I2C_CTRL, 0xEFFF},
|
||||
{NAU8540_REG_VMID_CTRL, 0x0000},
|
||||
{NAU8540_REG_MUTE, 0x0000},
|
||||
{NAU8540_REG_ANALOG_ADC1, 0x0011},
|
||||
{NAU8540_REG_ANALOG_ADC2, 0x0020},
|
||||
{NAU8540_REG_ANALOG_PWR, 0x0000},
|
||||
{NAU8540_REG_MIC_BIAS, 0x0004},
|
||||
{NAU8540_REG_REFERENCE, 0x0000},
|
||||
{NAU8540_REG_FEPGA1, 0x0000},
|
||||
{NAU8540_REG_FEPGA2, 0x0000},
|
||||
{NAU8540_REG_FEPGA3, 0x0101},
|
||||
{NAU8540_REG_FEPGA4, 0x0101},
|
||||
{NAU8540_REG_PWR, 0x0000},
|
||||
};
|
||||
|
||||
static bool nau8540_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case NAU8540_REG_POWER_MANAGEMENT ... NAU8540_REG_FLL_VCO_RSV:
|
||||
case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
|
||||
case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
|
||||
case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ADC_SAMPLE_RATE:
|
||||
case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
|
||||
case NAU8540_REG_P2P_CH1 ... NAU8540_REG_I2C_CTRL:
|
||||
case NAU8540_REG_I2C_DEVICE_ID:
|
||||
case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
|
||||
case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool nau8540_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case NAU8540_REG_SW_RESET ... NAU8540_REG_FLL_VCO_RSV:
|
||||
case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
|
||||
case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
|
||||
case NAU8540_REG_NOTCH_FIL1_CH1 ... NAU8540_REG_ADC_SAMPLE_RATE:
|
||||
case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
|
||||
case NAU8540_REG_GPIO_CTRL ... NAU8540_REG_I2C_CTRL:
|
||||
case NAU8540_REG_RST:
|
||||
case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
|
||||
case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nau8540_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case NAU8540_REG_SW_RESET:
|
||||
case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ALC_STATUS:
|
||||
case NAU8540_REG_P2P_CH1 ... NAU8540_REG_PEAK_CH4:
|
||||
case NAU8540_REG_I2C_DEVICE_ID:
|
||||
case NAU8540_REG_RST:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -12800, 3600);
|
||||
static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
|
||||
|
||||
static const struct snd_kcontrol_new nau8540_snd_controls[] = {
|
||||
SOC_SINGLE_TLV("Mic1 Volume", NAU8540_REG_DIGITAL_GAIN_CH1,
|
||||
0, 0x520, 0, adc_vol_tlv),
|
||||
SOC_SINGLE_TLV("Mic2 Volume", NAU8540_REG_DIGITAL_GAIN_CH2,
|
||||
0, 0x520, 0, adc_vol_tlv),
|
||||
SOC_SINGLE_TLV("Mic3 Volume", NAU8540_REG_DIGITAL_GAIN_CH3,
|
||||
0, 0x520, 0, adc_vol_tlv),
|
||||
SOC_SINGLE_TLV("Mic4 Volume", NAU8540_REG_DIGITAL_GAIN_CH4,
|
||||
0, 0x520, 0, adc_vol_tlv),
|
||||
|
||||
SOC_SINGLE_TLV("Frontend PGA1 Volume", NAU8540_REG_FEPGA3,
|
||||
0, 0x25, 0, fepga_gain_tlv),
|
||||
SOC_SINGLE_TLV("Frontend PGA2 Volume", NAU8540_REG_FEPGA3,
|
||||
8, 0x25, 0, fepga_gain_tlv),
|
||||
SOC_SINGLE_TLV("Frontend PGA3 Volume", NAU8540_REG_FEPGA4,
|
||||
0, 0x25, 0, fepga_gain_tlv),
|
||||
SOC_SINGLE_TLV("Frontend PGA4 Volume", NAU8540_REG_FEPGA4,
|
||||
8, 0x25, 0, fepga_gain_tlv),
|
||||
};
|
||||
|
||||
static const char * const adc_channel[] = {
|
||||
"ADC channel 1", "ADC channel 2", "ADC channel 3", "ADC channel 4"
|
||||
};
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
digital_ch4_enum, NAU8540_REG_DIGITAL_MUX, 6, adc_channel);
|
||||
|
||||
static const struct snd_kcontrol_new digital_ch4_mux =
|
||||
SOC_DAPM_ENUM("Digital CH4 Select", digital_ch4_enum);
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
digital_ch3_enum, NAU8540_REG_DIGITAL_MUX, 4, adc_channel);
|
||||
|
||||
static const struct snd_kcontrol_new digital_ch3_mux =
|
||||
SOC_DAPM_ENUM("Digital CH3 Select", digital_ch3_enum);
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
digital_ch2_enum, NAU8540_REG_DIGITAL_MUX, 2, adc_channel);
|
||||
|
||||
static const struct snd_kcontrol_new digital_ch2_mux =
|
||||
SOC_DAPM_ENUM("Digital CH2 Select", digital_ch2_enum);
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
digital_ch1_enum, NAU8540_REG_DIGITAL_MUX, 0, adc_channel);
|
||||
|
||||
static const struct snd_kcontrol_new digital_ch1_mux =
|
||||
SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_INPUT("MIC1"),
|
||||
SND_SOC_DAPM_INPUT("MIC2"),
|
||||
SND_SOC_DAPM_INPUT("MIC3"),
|
||||
SND_SOC_DAPM_INPUT("MIC4"),
|
||||
|
||||
SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC1", NULL,
|
||||
NAU8540_REG_POWER_MANAGEMENT, 0, 0),
|
||||
SND_SOC_DAPM_ADC("ADC2", NULL,
|
||||
NAU8540_REG_POWER_MANAGEMENT, 1, 0),
|
||||
SND_SOC_DAPM_ADC("ADC3", NULL,
|
||||
NAU8540_REG_POWER_MANAGEMENT, 2, 0),
|
||||
SND_SOC_DAPM_ADC("ADC4", NULL,
|
||||
NAU8540_REG_POWER_MANAGEMENT, 3, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MUX("Digital CH4 Mux",
|
||||
SND_SOC_NOPM, 0, 0, &digital_ch4_mux),
|
||||
SND_SOC_DAPM_MUX("Digital CH3 Mux",
|
||||
SND_SOC_NOPM, 0, 0, &digital_ch3_mux),
|
||||
SND_SOC_DAPM_MUX("Digital CH2 Mux",
|
||||
SND_SOC_NOPM, 0, 0, &digital_ch2_mux),
|
||||
SND_SOC_DAPM_MUX("Digital CH1 Mux",
|
||||
SND_SOC_NOPM, 0, 0, &digital_ch1_mux),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
|
||||
{"Frontend PGA1", NULL, "MIC1"},
|
||||
{"Frontend PGA2", NULL, "MIC2"},
|
||||
{"Frontend PGA3", NULL, "MIC3"},
|
||||
{"Frontend PGA4", NULL, "MIC4"},
|
||||
|
||||
{"ADC1", NULL, "Frontend PGA1"},
|
||||
{"ADC2", NULL, "Frontend PGA2"},
|
||||
{"ADC3", NULL, "Frontend PGA3"},
|
||||
{"ADC4", NULL, "Frontend PGA4"},
|
||||
|
||||
{"ADC CH1", NULL, "ADC1"},
|
||||
{"ADC CH2", NULL, "ADC2"},
|
||||
{"ADC CH3", NULL, "ADC3"},
|
||||
{"ADC CH4", NULL, "ADC4"},
|
||||
|
||||
{"ADC1", NULL, "MICBIAS1"},
|
||||
{"ADC2", NULL, "MICBIAS1"},
|
||||
{"ADC3", NULL, "MICBIAS2"},
|
||||
{"ADC4", NULL, "MICBIAS2"},
|
||||
|
||||
{"Digital CH1 Mux", "ADC channel 1", "ADC CH1"},
|
||||
{"Digital CH1 Mux", "ADC channel 2", "ADC CH2"},
|
||||
{"Digital CH1 Mux", "ADC channel 3", "ADC CH3"},
|
||||
{"Digital CH1 Mux", "ADC channel 4", "ADC CH4"},
|
||||
|
||||
{"Digital CH2 Mux", "ADC channel 1", "ADC CH1"},
|
||||
{"Digital CH2 Mux", "ADC channel 2", "ADC CH2"},
|
||||
{"Digital CH2 Mux", "ADC channel 3", "ADC CH3"},
|
||||
{"Digital CH2 Mux", "ADC channel 4", "ADC CH4"},
|
||||
|
||||
{"Digital CH3 Mux", "ADC channel 1", "ADC CH1"},
|
||||
{"Digital CH3 Mux", "ADC channel 2", "ADC CH2"},
|
||||
{"Digital CH3 Mux", "ADC channel 3", "ADC CH3"},
|
||||
{"Digital CH3 Mux", "ADC channel 4", "ADC CH4"},
|
||||
|
||||
{"Digital CH4 Mux", "ADC channel 1", "ADC CH1"},
|
||||
{"Digital CH4 Mux", "ADC channel 2", "ADC CH2"},
|
||||
{"Digital CH4 Mux", "ADC channel 3", "ADC CH3"},
|
||||
{"Digital CH4 Mux", "ADC channel 4", "ADC CH4"},
|
||||
|
||||
{"AIFTX", NULL, "Digital CH1 Mux"},
|
||||
{"AIFTX", NULL, "Digital CH2 Mux"},
|
||||
{"AIFTX", NULL, "Digital CH3 Mux"},
|
||||
{"AIFTX", NULL, "Digital CH4 Mux"},
|
||||
};
|
||||
|
||||
static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
|
||||
{
|
||||
int osrate;
|
||||
|
||||
if (osr >= ARRAY_SIZE(osr_adc_sel))
|
||||
return -EINVAL;
|
||||
osrate = osr_adc_sel[osr].osr;
|
||||
|
||||
if (rate * osr > CLK_ADC_MAX) {
|
||||
dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nau8540_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val_len = 0, osr;
|
||||
|
||||
/* CLK_ADC = OSR * FS
|
||||
* ADC clock frequency is defined as Over Sampling Rate (OSR)
|
||||
* multiplied by the audio sample rate (Fs). Note that the OSR and Fs
|
||||
* values must be selected such that the maximum frequency is less
|
||||
* than 6.144 MHz.
|
||||
*/
|
||||
regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr);
|
||||
osr &= NAU8540_ADC_OSR_MASK;
|
||||
if (nau8540_clock_check(nau8540, params_rate(params), osr))
|
||||
return -EINVAL;
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
|
||||
NAU8540_CLK_ADC_SRC_MASK,
|
||||
osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT);
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val_len |= NAU8540_I2S_DL_16;
|
||||
break;
|
||||
case 20:
|
||||
val_len |= NAU8540_I2S_DL_20;
|
||||
break;
|
||||
case 24:
|
||||
val_len |= NAU8540_I2S_DL_24;
|
||||
break;
|
||||
case 32:
|
||||
val_len |= NAU8540_I2S_DL_32;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
|
||||
NAU8540_I2S_DL_MASK, val_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int ctrl1_val = 0, ctrl2_val = 0;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
ctrl2_val |= NAU8540_I2S_MS_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
ctrl1_val |= NAU8540_I2S_BP_INV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
ctrl1_val |= NAU8540_I2S_DF_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
ctrl1_val |= NAU8540_I2S_DF_LEFT;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
ctrl1_val |= NAU8540_I2S_DF_RIGTH;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
|
||||
ctrl1_val |= NAU8540_I2S_PCMB_EN;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
|
||||
NAU8540_I2S_DL_MASK | NAU8540_I2S_DF_MASK |
|
||||
NAU8540_I2S_BP_INV | NAU8540_I2S_PCMB_EN, ctrl1_val);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
|
||||
NAU8540_I2S_MS_MASK | NAU8540_I2S_DO12_OE, ctrl2_val);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
|
||||
NAU8540_I2S_DO34_OE, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nau8540_set_tdm_slot - configure DAI TX TDM.
|
||||
* @dai: DAI
|
||||
* @tx_mask: bitmask representing active TX slots. Ex.
|
||||
* 0xf for normal 4 channel TDM.
|
||||
* 0xf0 for shifted 4 channel TDM
|
||||
* @rx_mask: no used.
|
||||
* @slots: Number of slots in use.
|
||||
* @slot_width: Width in bits for each slot.
|
||||
*
|
||||
* Configures a DAI for TDM operation. Only support 4 slots TDM.
|
||||
*/
|
||||
static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int ctrl2_val = 0, ctrl4_val = 0;
|
||||
|
||||
if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)))
|
||||
return -EINVAL;
|
||||
|
||||
ctrl4_val |= (NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN);
|
||||
if (tx_mask & 0xf0) {
|
||||
ctrl2_val = 4 * slot_width;
|
||||
ctrl4_val |= (tx_mask >> 4);
|
||||
} else {
|
||||
ctrl4_val |= tx_mask;
|
||||
}
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL4,
|
||||
NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN |
|
||||
NAU8540_TDM_TX_MASK, ctrl4_val);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
|
||||
NAU8540_I2S_DO12_OE, NAU8540_I2S_DO12_OE);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
|
||||
NAU8540_I2S_DO34_OE | NAU8540_I2S_TSLOT_L_MASK,
|
||||
NAU8540_I2S_DO34_OE | ctrl2_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_soc_dai_ops nau8540_dai_ops = {
|
||||
.hw_params = nau8540_hw_params,
|
||||
.set_fmt = nau8540_set_fmt,
|
||||
.set_tdm_slot = nau8540_set_tdm_slot,
|
||||
};
|
||||
|
||||
#define NAU8540_RATES SNDRV_PCM_RATE_8000_48000
|
||||
#define NAU8540_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
|
||||
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver nau8540_dai = {
|
||||
.name = "nau8540-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 4,
|
||||
.rates = NAU8540_RATES,
|
||||
.formats = NAU8540_FORMATS,
|
||||
},
|
||||
.ops = &nau8540_dai_ops,
|
||||
};
|
||||
|
||||
/**
|
||||
* nau8540_calc_fll_param - Calculate FLL parameters.
|
||||
* @fll_in: external clock provided to codec.
|
||||
* @fs: sampling rate.
|
||||
* @fll_param: Pointer to structure of FLL parameters.
|
||||
*
|
||||
* Calculate FLL parameters to configure codec.
|
||||
*
|
||||
* Returns 0 for success or negative error code.
|
||||
*/
|
||||
static int nau8540_calc_fll_param(unsigned int fll_in,
|
||||
unsigned int fs, struct nau8540_fll *fll_param)
|
||||
{
|
||||
u64 fvco, fvco_max;
|
||||
unsigned int fref, i, fvco_sel;
|
||||
|
||||
/* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
|
||||
* freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
|
||||
* FREF = freq_in / NAU8540_FLL_REF_DIV_MASK
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
|
||||
fref = fll_in / fll_pre_scalar[i].param;
|
||||
if (fref <= NAU_FREF_MAX)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(fll_pre_scalar))
|
||||
return -EINVAL;
|
||||
fll_param->clk_ref_div = fll_pre_scalar[i].val;
|
||||
|
||||
/* Choose the FLL ratio based on FREF */
|
||||
for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
|
||||
if (fref >= fll_ratio[i].param)
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(fll_ratio))
|
||||
return -EINVAL;
|
||||
fll_param->ratio = fll_ratio[i].val;
|
||||
|
||||
/* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
|
||||
* FDCO must be within the 90MHz - 124MHz or the FFL cannot be
|
||||
* guaranteed across the full range of operation.
|
||||
* FDCO = freq_out * 2 * mclk_src_scaling
|
||||
*/
|
||||
fvco_max = 0;
|
||||
fvco_sel = ARRAY_SIZE(mclk_src_scaling);
|
||||
for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
|
||||
fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
|
||||
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
|
||||
fvco_max < fvco) {
|
||||
fvco_max = fvco;
|
||||
fvco_sel = i;
|
||||
}
|
||||
}
|
||||
if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
|
||||
return -EINVAL;
|
||||
fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
|
||||
|
||||
/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
|
||||
* input based on FDCO, FREF and FLL ratio.
|
||||
*/
|
||||
fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
|
||||
fll_param->fll_int = (fvco >> 16) & 0x3FF;
|
||||
fll_param->fll_frac = fvco & 0xFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nau8540_fll_apply(struct regmap *regmap,
|
||||
struct nau8540_fll *fll_param)
|
||||
{
|
||||
regmap_update_bits(regmap, NAU8540_REG_CLOCK_SRC,
|
||||
NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK,
|
||||
NAU8540_CLK_SRC_MCLK | fll_param->mclk_src);
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL1,
|
||||
NAU8540_FLL_RATIO_MASK, fll_param->ratio);
|
||||
/* FLL 16-bit fractional input */
|
||||
regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac);
|
||||
/* FLL 10-bit integer input */
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL3,
|
||||
NAU8540_FLL_INTEGER_MASK, fll_param->fll_int);
|
||||
/* FLL pre-scaler */
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL4,
|
||||
NAU8540_FLL_REF_DIV_MASK,
|
||||
fll_param->clk_ref_div << NAU8540_FLL_REF_DIV_SFT);
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL5,
|
||||
NAU8540_FLL_CLK_SW_MASK, NAU8540_FLL_CLK_SW_REF);
|
||||
regmap_update_bits(regmap,
|
||||
NAU8540_REG_FLL6, NAU8540_DCO_EN, 0);
|
||||
if (fll_param->fll_frac) {
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL5,
|
||||
NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
|
||||
NAU8540_FLL_FTR_SW_MASK,
|
||||
NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
|
||||
NAU8540_FLL_FTR_SW_FILTER);
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL6,
|
||||
NAU8540_SDM_EN, NAU8540_SDM_EN);
|
||||
} else {
|
||||
regmap_update_bits(regmap, NAU8540_REG_FLL5,
|
||||
NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
|
||||
NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU);
|
||||
regmap_update_bits(regmap,
|
||||
NAU8540_REG_FLL6, NAU8540_SDM_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* freq_out must be 256*Fs in order to achieve the best performance */
|
||||
static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
struct nau8540_fll fll_param;
|
||||
int ret, fs;
|
||||
|
||||
switch (pll_id) {
|
||||
case NAU8540_CLK_FLL_MCLK:
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
|
||||
NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK);
|
||||
break;
|
||||
|
||||
case NAU8540_CLK_FLL_BLK:
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
|
||||
NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
|
||||
break;
|
||||
|
||||
case NAU8540_CLK_FLL_FS:
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
|
||||
NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(nau8540->dev, "Invalid clock id (%d)\n", pll_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
|
||||
freq_out, pll_id);
|
||||
|
||||
fs = freq_out / 256;
|
||||
ret = nau8540_calc_fll_param(freq_in, fs, &fll_param);
|
||||
if (ret < 0) {
|
||||
dev_err(nau8540->dev, "Unsupported input clock %d\n", freq_in);
|
||||
return ret;
|
||||
}
|
||||
dev_dbg(nau8540->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
|
||||
fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
|
||||
fll_param.fll_int, fll_param.clk_ref_div);
|
||||
|
||||
nau8540_fll_apply(nau8540->regmap, &fll_param);
|
||||
mdelay(2);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
|
||||
NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nau8540_set_sysclk(struct snd_soc_codec *codec,
|
||||
int clk_id, int source, unsigned int freq, int dir)
|
||||
{
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case NAU8540_CLK_DIS:
|
||||
case NAU8540_CLK_MCLK:
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
|
||||
NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_MCLK);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
|
||||
NAU8540_DCO_EN, 0);
|
||||
break;
|
||||
|
||||
case NAU8540_CLK_INTERNAL:
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
|
||||
NAU8540_DCO_EN, NAU8540_DCO_EN);
|
||||
regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
|
||||
NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(nau8540->dev, "Invalid clock id (%d)\n", clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
|
||||
freq, clk_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nau8540_reset_chip(struct regmap *regmap)
|
||||
{
|
||||
regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
|
||||
regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
|
||||
}
|
||||
|
||||
static void nau8540_init_regs(struct nau8540 *nau8540)
|
||||
{
|
||||
struct regmap *regmap = nau8540->regmap;
|
||||
|
||||
/* Enable Bias/VMID/VMID Tieoff */
|
||||
regmap_update_bits(regmap, NAU8540_REG_VMID_CTRL,
|
||||
NAU8540_VMID_EN | NAU8540_VMID_SEL_MASK,
|
||||
NAU8540_VMID_EN | (0x2 << NAU8540_VMID_SEL_SFT));
|
||||
regmap_update_bits(regmap, NAU8540_REG_REFERENCE,
|
||||
NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN,
|
||||
NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN);
|
||||
mdelay(2);
|
||||
regmap_update_bits(regmap, NAU8540_REG_MIC_BIAS,
|
||||
NAU8540_PU_PRE, NAU8540_PU_PRE);
|
||||
regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
|
||||
NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN,
|
||||
NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN);
|
||||
/* ADC OSR selection, CLK_ADC = Fs * OSR */
|
||||
regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
|
||||
NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
|
||||
}
|
||||
|
||||
static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_cache_only(nau8540->regmap, true);
|
||||
regcache_mark_dirty(nau8540->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_cache_only(nau8540->regmap, false);
|
||||
regcache_sync(nau8540->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver nau8540_codec_driver = {
|
||||
.set_sysclk = nau8540_set_sysclk,
|
||||
.set_pll = nau8540_set_pll,
|
||||
.suspend = nau8540_suspend,
|
||||
.resume = nau8540_resume,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.component_driver = {
|
||||
.controls = nau8540_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(nau8540_snd_controls),
|
||||
.dapm_widgets = nau8540_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(nau8540_dapm_widgets),
|
||||
.dapm_routes = nau8540_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(nau8540_dapm_routes),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config nau8540_regmap_config = {
|
||||
.val_bits = 16,
|
||||
.reg_bits = 16,
|
||||
|
||||
.max_register = NAU8540_REG_MAX,
|
||||
.readable_reg = nau8540_readable_reg,
|
||||
.writeable_reg = nau8540_writeable_reg,
|
||||
.volatile_reg = nau8540_volatile_reg,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = nau8540_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults),
|
||||
};
|
||||
|
||||
static int nau8540_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &i2c->dev;
|
||||
struct nau8540 *nau8540 = dev_get_platdata(dev);
|
||||
int ret, value;
|
||||
|
||||
if (!nau8540) {
|
||||
nau8540 = devm_kzalloc(dev, sizeof(*nau8540), GFP_KERNEL);
|
||||
if (!nau8540)
|
||||
return -ENOMEM;
|
||||
}
|
||||
i2c_set_clientdata(i2c, nau8540);
|
||||
|
||||
nau8540->regmap = devm_regmap_init_i2c(i2c, &nau8540_regmap_config);
|
||||
if (IS_ERR(nau8540->regmap))
|
||||
return PTR_ERR(nau8540->regmap);
|
||||
ret = regmap_read(nau8540->regmap, NAU8540_REG_I2C_DEVICE_ID, &value);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read device id from the NAU85L40: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nau8540->dev = dev;
|
||||
nau8540_reset_chip(nau8540->regmap);
|
||||
nau8540_init_regs(nau8540);
|
||||
|
||||
return snd_soc_register_codec(dev,
|
||||
&nau8540_codec_driver, &nau8540_dai, 1);
|
||||
}
|
||||
|
||||
static int nau8540_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id nau8540_i2c_ids[] = {
|
||||
{ "nau8540", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id nau8540_of_ids[] = {
|
||||
{ .compatible = "nuvoton,nau8540", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, nau8540_of_ids);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver nau8540_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "nau8540",
|
||||
.of_match_table = of_match_ptr(nau8540_of_ids),
|
||||
},
|
||||
.probe = nau8540_i2c_probe,
|
||||
.remove = nau8540_i2c_remove,
|
||||
.id_table = nau8540_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(nau8540_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC NAU85L40 driver");
|
||||
MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* NAU85L40 ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2016 Nuvoton Technology Corp.
|
||||
* Author: John Hsu <KCHSU0@nuvoton.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __NAU8540_H__
|
||||
#define __NAU8540_H__
|
||||
|
||||
#define NAU8540_REG_SW_RESET 0x00
|
||||
#define NAU8540_REG_POWER_MANAGEMENT 0x01
|
||||
#define NAU8540_REG_CLOCK_CTRL 0x02
|
||||
#define NAU8540_REG_CLOCK_SRC 0x03
|
||||
#define NAU8540_REG_FLL1 0x04
|
||||
#define NAU8540_REG_FLL2 0x05
|
||||
#define NAU8540_REG_FLL3 0x06
|
||||
#define NAU8540_REG_FLL4 0x07
|
||||
#define NAU8540_REG_FLL5 0x08
|
||||
#define NAU8540_REG_FLL6 0x09
|
||||
#define NAU8540_REG_FLL_VCO_RSV 0x0A
|
||||
#define NAU8540_REG_PCM_CTRL0 0x10
|
||||
#define NAU8540_REG_PCM_CTRL1 0x11
|
||||
#define NAU8540_REG_PCM_CTRL2 0x12
|
||||
#define NAU8540_REG_PCM_CTRL3 0x13
|
||||
#define NAU8540_REG_PCM_CTRL4 0x14
|
||||
#define NAU8540_REG_ALC_CONTROL_1 0x20
|
||||
#define NAU8540_REG_ALC_CONTROL_2 0x21
|
||||
#define NAU8540_REG_ALC_CONTROL_3 0x22
|
||||
#define NAU8540_REG_ALC_CONTROL_4 0x23
|
||||
#define NAU8540_REG_ALC_CONTROL_5 0x24
|
||||
#define NAU8540_REG_ALC_GAIN_CH12 0x2D
|
||||
#define NAU8540_REG_ALC_GAIN_CH34 0x2E
|
||||
#define NAU8540_REG_ALC_STATUS 0x2F
|
||||
#define NAU8540_REG_NOTCH_FIL1_CH1 0x30
|
||||
#define NAU8540_REG_NOTCH_FIL2_CH1 0x31
|
||||
#define NAU8540_REG_NOTCH_FIL1_CH2 0x32
|
||||
#define NAU8540_REG_NOTCH_FIL2_CH2 0x33
|
||||
#define NAU8540_REG_NOTCH_FIL1_CH3 0x34
|
||||
#define NAU8540_REG_NOTCH_FIL2_CH3 0x35
|
||||
#define NAU8540_REG_NOTCH_FIL1_CH4 0x36
|
||||
#define NAU8540_REG_NOTCH_FIL2_CH4 0x37
|
||||
#define NAU8540_REG_HPF_FILTER_CH12 0x38
|
||||
#define NAU8540_REG_HPF_FILTER_CH34 0x39
|
||||
#define NAU8540_REG_ADC_SAMPLE_RATE 0x3A
|
||||
#define NAU8540_REG_DIGITAL_GAIN_CH1 0x40
|
||||
#define NAU8540_REG_DIGITAL_GAIN_CH2 0x41
|
||||
#define NAU8540_REG_DIGITAL_GAIN_CH3 0x42
|
||||
#define NAU8540_REG_DIGITAL_GAIN_CH4 0x43
|
||||
#define NAU8540_REG_DIGITAL_MUX 0x44
|
||||
#define NAU8540_REG_P2P_CH1 0x48
|
||||
#define NAU8540_REG_P2P_CH2 0x49
|
||||
#define NAU8540_REG_P2P_CH3 0x4A
|
||||
#define NAU8540_REG_P2P_CH4 0x4B
|
||||
#define NAU8540_REG_PEAK_CH1 0x4C
|
||||
#define NAU8540_REG_PEAK_CH2 0x4D
|
||||
#define NAU8540_REG_PEAK_CH3 0x4E
|
||||
#define NAU8540_REG_PEAK_CH4 0x4F
|
||||
#define NAU8540_REG_GPIO_CTRL 0x50
|
||||
#define NAU8540_REG_MISC_CTRL 0x51
|
||||
#define NAU8540_REG_I2C_CTRL 0x52
|
||||
#define NAU8540_REG_I2C_DEVICE_ID 0x58
|
||||
#define NAU8540_REG_RST 0x5A
|
||||
#define NAU8540_REG_VMID_CTRL 0x60
|
||||
#define NAU8540_REG_MUTE 0x61
|
||||
#define NAU8540_REG_ANALOG_ADC1 0x64
|
||||
#define NAU8540_REG_ANALOG_ADC2 0x65
|
||||
#define NAU8540_REG_ANALOG_PWR 0x66
|
||||
#define NAU8540_REG_MIC_BIAS 0x67
|
||||
#define NAU8540_REG_REFERENCE 0x68
|
||||
#define NAU8540_REG_FEPGA1 0x69
|
||||
#define NAU8540_REG_FEPGA2 0x6A
|
||||
#define NAU8540_REG_FEPGA3 0x6B
|
||||
#define NAU8540_REG_FEPGA4 0x6C
|
||||
#define NAU8540_REG_PWR 0x6D
|
||||
#define NAU8540_REG_MAX NAU8540_REG_PWR
|
||||
|
||||
|
||||
/* POWER_MANAGEMENT (0x01) */
|
||||
#define NAU8540_ADC4_EN (0x1 << 3)
|
||||
#define NAU8540_ADC3_EN (0x1 << 2)
|
||||
#define NAU8540_ADC2_EN (0x1 << 1)
|
||||
#define NAU8540_ADC1_EN 0x1
|
||||
|
||||
/* CLOCK_CTRL (0x02) */
|
||||
#define NAU8540_CLK_ADC_EN (0x1 << 15)
|
||||
#define NAU8540_CLK_I2S_EN (0x1 << 1)
|
||||
|
||||
/* CLOCK_SRC (0x03) */
|
||||
#define NAU8540_CLK_SRC_SFT 15
|
||||
#define NAU8540_CLK_SRC_MASK (1 << NAU8540_CLK_SRC_SFT)
|
||||
#define NAU8540_CLK_SRC_VCO (1 << NAU8540_CLK_SRC_SFT)
|
||||
#define NAU8540_CLK_SRC_MCLK (0 << NAU8540_CLK_SRC_SFT)
|
||||
#define NAU8540_CLK_ADC_SRC_SFT 6
|
||||
#define NAU8540_CLK_ADC_SRC_MASK (0x3 << NAU8540_CLK_ADC_SRC_SFT)
|
||||
#define NAU8540_CLK_MCLK_SRC_MASK 0xf
|
||||
|
||||
/* FLL1 (0x04) */
|
||||
#define NAU8540_FLL_RATIO_MASK 0x7f
|
||||
|
||||
/* FLL3 (0x06) */
|
||||
#define NAU8540_FLL_CLK_SRC_SFT 10
|
||||
#define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT)
|
||||
#define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT)
|
||||
#define NAU8540_FLL_CLK_SRC_BLK (0x2 << NAU8540_FLL_CLK_SRC_SFT)
|
||||
#define NAU8540_FLL_CLK_SRC_FS (0x3 << NAU8540_FLL_CLK_SRC_SFT)
|
||||
#define NAU8540_FLL_INTEGER_MASK 0x3ff
|
||||
|
||||
/* FLL4 (0x07) */
|
||||
#define NAU8540_FLL_REF_DIV_SFT 10
|
||||
#define NAU8540_FLL_REF_DIV_MASK (0x3 << NAU8540_FLL_REF_DIV_SFT)
|
||||
|
||||
/* FLL5 (0x08) */
|
||||
#define NAU8540_FLL_PDB_DAC_EN (0x1 << 15)
|
||||
#define NAU8540_FLL_LOOP_FTR_EN (0x1 << 14)
|
||||
#define NAU8540_FLL_CLK_SW_MASK (0x1 << 13)
|
||||
#define NAU8540_FLL_CLK_SW_N2 (0x1 << 13)
|
||||
#define NAU8540_FLL_CLK_SW_REF (0x0 << 13)
|
||||
#define NAU8540_FLL_FTR_SW_MASK (0x1 << 12)
|
||||
#define NAU8540_FLL_FTR_SW_ACCU (0x1 << 12)
|
||||
#define NAU8540_FLL_FTR_SW_FILTER (0x0 << 12)
|
||||
|
||||
/* FLL6 (0x9) */
|
||||
#define NAU8540_DCO_EN (0x1 << 15)
|
||||
#define NAU8540_SDM_EN (0x1 << 14)
|
||||
|
||||
/* PCM_CTRL0 (0x10) */
|
||||
#define NAU8540_I2S_BP_SFT 7
|
||||
#define NAU8540_I2S_BP_INV (0x1 << NAU8540_I2S_BP_SFT)
|
||||
#define NAU8540_I2S_PCMB_SFT 6
|
||||
#define NAU8540_I2S_PCMB_EN (0x1 << NAU8540_I2S_PCMB_SFT)
|
||||
#define NAU8540_I2S_DL_SFT 2
|
||||
#define NAU8540_I2S_DL_MASK (0x3 << NAU8540_I2S_DL_SFT)
|
||||
#define NAU8540_I2S_DL_16 (0 << NAU8540_I2S_DL_SFT)
|
||||
#define NAU8540_I2S_DL_20 (0x1 << NAU8540_I2S_DL_SFT)
|
||||
#define NAU8540_I2S_DL_24 (0x2 << NAU8540_I2S_DL_SFT)
|
||||
#define NAU8540_I2S_DL_32 (0x3 << NAU8540_I2S_DL_SFT)
|
||||
#define NAU8540_I2S_DF_MASK 0x3
|
||||
#define NAU8540_I2S_DF_RIGTH 0
|
||||
#define NAU8540_I2S_DF_LEFT 0x1
|
||||
#define NAU8540_I2S_DF_I2S 0x2
|
||||
#define NAU8540_I2S_DF_PCM_AB 0x3
|
||||
|
||||
/* PCM_CTRL1 (0x11) */
|
||||
#define NAU8540_I2S_LRC_DIV_SFT 12
|
||||
#define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT)
|
||||
#define NAU8540_I2S_DO12_OE (0x1 << 4)
|
||||
#define NAU8540_I2S_MS_SFT 3
|
||||
#define NAU8540_I2S_MS_MASK (0x1 << NAU8540_I2S_MS_SFT)
|
||||
#define NAU8540_I2S_MS_MASTER (0x1 << NAU8540_I2S_MS_SFT)
|
||||
#define NAU8540_I2S_MS_SLAVE (0x0 << NAU8540_I2S_MS_SFT)
|
||||
#define NAU8540_I2S_BLK_DIV_MASK 0x7
|
||||
|
||||
/* PCM_CTRL1 (0x12) */
|
||||
#define NAU8540_I2S_DO34_OE (0x1 << 11)
|
||||
#define NAU8540_I2S_TSLOT_L_MASK 0x3ff
|
||||
|
||||
/* PCM_CTRL4 (0x14) */
|
||||
#define NAU8540_TDM_MODE (0x1 << 15)
|
||||
#define NAU8540_TDM_OFFSET_EN (0x1 << 14)
|
||||
#define NAU8540_TDM_TX_MASK 0xf
|
||||
|
||||
/* ADC_SAMPLE_RATE (0x3A) */
|
||||
#define NAU8540_ADC_OSR_MASK 0x3
|
||||
#define NAU8540_ADC_OSR_256 0x3
|
||||
#define NAU8540_ADC_OSR_128 0x2
|
||||
#define NAU8540_ADC_OSR_64 0x1
|
||||
#define NAU8540_ADC_OSR_32 0x0
|
||||
|
||||
/* VMID_CTRL (0x60) */
|
||||
#define NAU8540_VMID_EN (1 << 6)
|
||||
#define NAU8540_VMID_SEL_SFT 4
|
||||
#define NAU8540_VMID_SEL_MASK (0x3 << NAU8540_VMID_SEL_SFT)
|
||||
|
||||
/* MIC_BIAS (0x67) */
|
||||
#define NAU8540_PU_PRE (0x1 << 8)
|
||||
|
||||
/* REFERENCE (0x68) */
|
||||
#define NAU8540_PRECHARGE_DIS (0x1 << 13)
|
||||
#define NAU8540_GLOBAL_BIAS_EN (0x1 << 12)
|
||||
|
||||
|
||||
/* System Clock Source */
|
||||
enum {
|
||||
NAU8540_CLK_DIS,
|
||||
NAU8540_CLK_MCLK,
|
||||
NAU8540_CLK_INTERNAL,
|
||||
NAU8540_CLK_FLL_MCLK,
|
||||
NAU8540_CLK_FLL_BLK,
|
||||
NAU8540_CLK_FLL_FS,
|
||||
};
|
||||
|
||||
struct nau8540 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
struct nau8540_fll {
|
||||
int mclk_src;
|
||||
int ratio;
|
||||
int fll_frac;
|
||||
int fll_int;
|
||||
int clk_ref_div;
|
||||
};
|
||||
|
||||
struct nau8540_fll_attr {
|
||||
unsigned int param;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
/* over sampling rate */
|
||||
struct nau8540_osr_attr {
|
||||
unsigned int osr;
|
||||
unsigned int clk_src;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __NAU8540_H__ */
|
|
@ -1231,7 +1231,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val_len = 0, osr;
|
||||
unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
|
||||
|
||||
nau8825_sema_acquire(nau8825, 3 * HZ);
|
||||
|
||||
|
@ -1261,6 +1261,24 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
|
|||
osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
|
||||
}
|
||||
|
||||
/* make BCLK and LRC divde configuration if the codec as master. */
|
||||
regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, &ctrl_val);
|
||||
if (ctrl_val & NAU8825_I2S_MS_MASTER) {
|
||||
/* get the bclk and fs ratio */
|
||||
bclk_fs = snd_soc_params_to_bclk(params) / params_rate(params);
|
||||
if (bclk_fs <= 32)
|
||||
bclk_div = 2;
|
||||
else if (bclk_fs <= 64)
|
||||
bclk_div = 1;
|
||||
else if (bclk_fs <= 128)
|
||||
bclk_div = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
|
||||
NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK,
|
||||
((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div);
|
||||
}
|
||||
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
val_len |= NAU8825_I2S_DL_16;
|
||||
|
|
|
@ -402,10 +402,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
|
|||
u32 val, mask, shift, reg;
|
||||
unsigned int rate, fmt, ratio, max_ratio;
|
||||
int i, min_frame_size;
|
||||
snd_pcm_format_t format;
|
||||
|
||||
rate = params_rate(params);
|
||||
format = params_format(params);
|
||||
|
||||
ratio = pcm3168a->sysclk / rate;
|
||||
|
||||
|
|
|
@ -1163,6 +1163,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P")
|
||||
}
|
||||
},
|
||||
{
|
||||
.ident = "Intel Gemini Lake",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
|
||||
}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
|
|
@ -995,7 +995,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
|
|||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
rt5640->hp_mute = 1;
|
||||
usleep_range(70000, 75000);
|
||||
msleep(70);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1059,7 +1059,7 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
|
|||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
if (!rt5640->hp_mute)
|
||||
usleep_range(80000, 85000);
|
||||
msleep(80);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1227,6 +1227,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
|
|||
RT5640_PWR_DAC_L1_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5640_PWR_DIG1,
|
||||
RT5640_PWR_DAC_R1_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5640_PWR_DIG1,
|
||||
RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5640_PWR_DIG1,
|
||||
RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
|
||||
/* SPK/OUT Mixer */
|
||||
SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
|
||||
0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
|
||||
|
@ -1322,10 +1326,6 @@ static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = {
|
|||
rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
|
||||
SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
|
||||
RT5640_PWR_MA_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5640_PWR_DIG1,
|
||||
RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5640_PWR_DIG1,
|
||||
RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("MONOP"),
|
||||
SND_SOC_DAPM_OUTPUT("MONON"),
|
||||
|
@ -2313,6 +2313,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
|
|||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt5640_acpi_match[] = {
|
||||
{ "INT33CA", 0 },
|
||||
{ "10EC3276", 0 },
|
||||
{ "10EC5640", 0 },
|
||||
{ "10EC5642", 0 },
|
||||
{ "INTCCFFD", 0 },
|
||||
|
|
|
@ -3109,7 +3109,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
|||
unsigned int val;
|
||||
|
||||
if (jack_insert) {
|
||||
regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
|
||||
regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
|
||||
|
||||
/* for jack type detect */
|
||||
snd_soc_dapm_force_enable_pin(dapm, "LDO2");
|
||||
|
@ -3545,8 +3545,10 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
|
|||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt5645_acpi_match[] = {
|
||||
{ "10EC5645", 0 },
|
||||
{ "10EC5648", 0 },
|
||||
{ "10EC5650", 0 },
|
||||
{ "10EC5640", 0 },
|
||||
{ "10EC3270", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
|
||||
|
@ -3658,8 +3660,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
|||
GPIOD_IN);
|
||||
|
||||
if (IS_ERR(rt5645->gpiod_hp_det)) {
|
||||
dev_err(&i2c->dev, "failed to initialize gpiod\n");
|
||||
return PTR_ERR(rt5645->gpiod_hp_det);
|
||||
dev_info(&i2c->dev, "failed to initialize gpiod\n");
|
||||
ret = PTR_ERR(rt5645->gpiod_hp_det);
|
||||
/*
|
||||
* Continue if optional gpiod is missing, bail for all other
|
||||
* errors, including -EPROBE_DEFER
|
||||
*/
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
|
||||
|
|
|
@ -1150,28 +1150,28 @@ static const char * const rt5659_data_select[] = {
|
|||
"L/R", "R/L", "L/L", "R/R"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
|
||||
RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
|
||||
RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
|
||||
RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
|
||||
RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
|
||||
RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
|
||||
RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
|
||||
RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
|
||||
RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux =
|
||||
|
@ -1207,31 +1207,31 @@ static unsigned int rt5659_asrc_clk_map_values[] = {
|
|||
0, 1, 2, 3, 5, 6,
|
||||
};
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
static const SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(
|
||||
rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
|
||||
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
|
||||
|
||||
|
@ -1930,14 +1930,14 @@ static const char * const rt5659_dac2_src[] = {
|
|||
"IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dac_l2_enum, RT5659_DAC_CTRL,
|
||||
RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_dac_l2_mux =
|
||||
SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dac_r2_enum, RT5659_DAC_CTRL,
|
||||
RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
|
||||
|
||||
|
@ -1951,7 +1951,7 @@ static const char * const rt5659_sto1_adc1_src[] = {
|
|||
"DAC MIX", "ADC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER,
|
||||
RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
|
||||
|
||||
|
@ -1964,7 +1964,7 @@ static const char * const rt5659_sto1_adc_src[] = {
|
|||
"ADC1", "ADC2"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
|
||||
RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
|
||||
|
||||
|
@ -1977,7 +1977,7 @@ static const char * const rt5659_sto1_adc2_src[] = {
|
|||
"DAC MIX", "DMIC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER,
|
||||
RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
|
||||
|
||||
|
@ -1990,7 +1990,7 @@ static const char * const rt5659_sto1_dmic_src[] = {
|
|||
"DMIC1", "DMIC2"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
|
||||
RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src);
|
||||
|
||||
|
@ -2004,7 +2004,7 @@ static const char * const rt5659_mono_adc_l2_src[] = {
|
|||
"Mono DAC MIXL", "DMIC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src);
|
||||
|
||||
|
@ -2018,7 +2018,7 @@ static const char * const rt5659_mono_adc_l1_src[] = {
|
|||
"Mono DAC MIXL", "ADC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src);
|
||||
|
||||
|
@ -2031,14 +2031,14 @@ static const char * const rt5659_mono_adc_src[] = {
|
|||
"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
|
||||
SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src);
|
||||
|
||||
|
@ -2051,7 +2051,7 @@ static const char * const rt5659_mono_dmic_l_src[] = {
|
|||
"DMIC1 L", "DMIC2 L"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src);
|
||||
|
||||
|
@ -2064,7 +2064,7 @@ static const char * const rt5659_mono_adc_r2_src[] = {
|
|||
"Mono DAC MIXR", "DMIC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src);
|
||||
|
||||
|
@ -2077,7 +2077,7 @@ static const char * const rt5659_mono_adc_r1_src[] = {
|
|||
"Mono DAC MIXR", "ADC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src);
|
||||
|
||||
|
@ -2090,7 +2090,7 @@ static const char * const rt5659_mono_dmic_r_src[] = {
|
|||
"DMIC1 R", "DMIC2 R"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER,
|
||||
RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src);
|
||||
|
||||
|
@ -2104,14 +2104,14 @@ static const char * const rt5659_dac1_src[] = {
|
|||
"IF1 DAC1", "IF2 DAC", "IF3 DAC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dac_r1_enum, RT5659_AD_DA_MIXER,
|
||||
RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_dac_r1_mux =
|
||||
SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dac_l1_enum, RT5659_AD_DA_MIXER,
|
||||
RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src);
|
||||
|
||||
|
@ -2124,14 +2124,14 @@ static const char * const rt5659_dig_dac_mix_src[] = {
|
|||
"Stereo DAC Mixer", "Mono DAC Mixer"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER,
|
||||
RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
|
||||
SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER,
|
||||
RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src);
|
||||
|
||||
|
@ -2144,14 +2144,14 @@ static const char * const rt5659_alg_dac1_src[] = {
|
|||
"DAC", "Stereo DAC Mixer"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX,
|
||||
RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
|
||||
SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX,
|
||||
RT5659_A_DACR1_SFT, rt5659_alg_dac1_src);
|
||||
|
||||
|
@ -2164,14 +2164,14 @@ static const char * const rt5659_alg_dac2_src[] = {
|
|||
"Stereo DAC Mixer", "Mono DAC Mixer"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX,
|
||||
RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
|
||||
SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX,
|
||||
RT5659_A_DACR2_SFT, rt5659_alg_dac2_src);
|
||||
|
||||
|
@ -2184,7 +2184,7 @@ static const char * const rt5659_if2_adc_in_src[] = {
|
|||
"IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA,
|
||||
RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src);
|
||||
|
||||
|
@ -2197,7 +2197,7 @@ static const char * const rt5659_if3_adc_in_src[] = {
|
|||
"IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA,
|
||||
RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src);
|
||||
|
||||
|
@ -2210,14 +2210,14 @@ static const char * const rt5659_pdm_src[] = {
|
|||
"Mono DAC", "Stereo DAC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
|
||||
RT5659_PDM1_L_SFT, rt5659_pdm_src);
|
||||
|
||||
static const struct snd_kcontrol_new rt5659_pdm_l_mux =
|
||||
SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL,
|
||||
RT5659_PDM1_R_SFT, rt5659_pdm_src);
|
||||
|
||||
|
@ -2230,7 +2230,7 @@ static const char * const rt5659_spdif_src[] = {
|
|||
"IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_spdif_enum, RT5659_SPDIF_CTRL,
|
||||
RT5659_SPDIF_SEL_SFT, rt5659_spdif_src);
|
||||
|
||||
|
@ -2250,7 +2250,7 @@ static const char * const rt5659_rx_adc_data_src[] = {
|
|||
"NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(
|
||||
static SOC_ENUM_SINGLE_DECL(
|
||||
rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2,
|
||||
RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src);
|
||||
|
||||
|
@ -4018,7 +4018,7 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
|
|||
GPIOD_OUT_HIGH);
|
||||
|
||||
/* Sleep for 300 ms miniumum */
|
||||
usleep_range(300000, 350000);
|
||||
msleep(300);
|
||||
|
||||
rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
|
||||
if (IS_ERR(rt5659->regmap)) {
|
||||
|
@ -4230,10 +4230,9 @@ static struct acpi_device_id rt5659_acpi_match[] = {
|
|||
MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
|
||||
#endif
|
||||
|
||||
struct i2c_driver rt5659_i2c_driver = {
|
||||
static struct i2c_driver rt5659_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rt5659",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(rt5659_of_match),
|
||||
.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
|
||||
},
|
||||
|
|
|
@ -526,10 +526,10 @@ static const char * const rt5660_data_select[] = {
|
|||
"L/R", "R/L", "L/L", "R/R"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum,
|
||||
RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select);
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum,
|
||||
static SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum,
|
||||
RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select);
|
||||
|
||||
static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux =
|
||||
|
@ -1152,7 +1152,7 @@ static int rt5660_resume(struct snd_soc_codec *codec)
|
|||
struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (rt5660->pdata.poweroff_codec_in_suspend)
|
||||
usleep_range(350000, 400000);
|
||||
msleep(350);
|
||||
|
||||
regcache_cache_only(rt5660->regmap, false);
|
||||
regcache_sync(rt5660->regmap);
|
||||
|
|
|
@ -2814,6 +2814,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
|
|||
static const struct acpi_device_id rt5670_acpi_match[] = {
|
||||
{ "10EC5670", 0},
|
||||
{ "10EC5672", 0},
|
||||
{ "10EC5640", 0}, /* quirk */
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
|
|
@ -1393,6 +1393,12 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
|
|||
snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c);
|
||||
snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay is needed to reduce pop-noise after syncing back the
|
||||
* registers
|
||||
*/
|
||||
mdelay(50);
|
||||
} else {
|
||||
/*
|
||||
* Do soft reset to this codec instance in order to clear
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
|
@ -855,6 +855,8 @@ ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
|
|||
ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
|
||||
ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
|
||||
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
|
||||
|
||||
|
@ -1944,7 +1946,10 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
|||
if (ret)
|
||||
goto err_adsp2_codec_probe;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
|
|
|
@ -778,6 +778,11 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
|
|||
SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
|
||||
SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
|
||||
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP4", 4),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
|
||||
|
@ -2279,7 +2284,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
|
|||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_mono(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#define WM8731_CACHEREGNUM 10
|
||||
|
||||
#define WM8731_SYSCLK_MCLK 0
|
||||
#define WM8731_SYSCLK_XTAL 1
|
||||
#define WM8731_SYSCLK_MCLK 2
|
||||
|
||||
#define WM8731_DAI 0
|
||||
|
||||
|
|
|
@ -37,8 +37,6 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
|
|||
"DVDD",
|
||||
};
|
||||
|
||||
#define WM8741_NUM_RATES 6
|
||||
|
||||
/* codec private data */
|
||||
struct wm8741_priv {
|
||||
struct wm8741_platform_data pdata;
|
||||
|
|
|
@ -280,6 +280,7 @@ static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
|
|||
static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
|
||||
|
||||
static const struct snd_kcontrol_new wm8753_snd_controls[] = {
|
||||
SOC_SINGLE("Hi-Fi DAC Left/Right channel Swap", WM8753_HIFI, 5, 1, 0),
|
||||
SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0,
|
||||
|
@ -1087,7 +1088,7 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec,
|
|||
{
|
||||
u16 ioctl, hifi;
|
||||
|
||||
hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f;
|
||||
hifi = snd_soc_read(codec, WM8753_HIFI) & 0x013f;
|
||||
ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae;
|
||||
|
||||
/* set master/slave audio interface */
|
||||
|
|
|
@ -1062,8 +1062,12 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
|
|||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
|
|
|
@ -1321,10 +1321,14 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
|
|||
struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
||||
int ret;
|
||||
|
||||
priv->core.arizona->dapm = dapm;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
ret = arizona_init_spk(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_gpio(codec);
|
||||
arizona_init_notifiers(codec);
|
||||
|
||||
|
|
|
@ -2473,7 +2473,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
|||
|
||||
ret = wm_adsp2_ena(dsp);
|
||||
if (ret != 0)
|
||||
goto err_mutex;
|
||||
goto err_mem;
|
||||
|
||||
ret = wm_adsp_load(dsp);
|
||||
if (ret != 0)
|
||||
|
@ -2492,14 +2492,14 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
|||
if (ret != 0)
|
||||
goto err_ena;
|
||||
|
||||
dsp->booted = true;
|
||||
|
||||
/* Turn DSP back off until we are ready to run */
|
||||
ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA, 0);
|
||||
if (ret != 0)
|
||||
goto err_ena;
|
||||
|
||||
dsp->booted = true;
|
||||
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
|
||||
return;
|
||||
|
@ -2507,6 +2507,9 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
|||
err_ena:
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
|
||||
err_mem:
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_MEM_ENA, 0);
|
||||
err_mutex:
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
}
|
||||
|
@ -2523,6 +2526,43 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
|
|||
adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
|
||||
}
|
||||
|
||||
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = dsp->preloaded;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
|
||||
|
||||
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
char preload[32];
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift);
|
||||
|
||||
dsp->preloaded = ucontrol->value.integer.value[0];
|
||||
|
||||
if (ucontrol->value.integer.value[0])
|
||||
snd_soc_dapm_force_enable_pin(dapm, preload);
|
||||
else
|
||||
snd_soc_dapm_disable_pin(dapm, preload);
|
||||
|
||||
snd_soc_dapm_sync(dapm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
|
||||
|
||||
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event,
|
||||
unsigned int freq)
|
||||
|
@ -2538,6 +2578,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
|||
queue_work(system_unbound_wq, &dsp->boot_work);
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
wm_adsp_debugfs_clear(dsp);
|
||||
|
||||
dsp->fw_id = 0;
|
||||
|
@ -2553,6 +2595,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
|||
|
||||
wm_adsp_free_alg_regions(dsp);
|
||||
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
|
||||
adsp_dbg(dsp, "Shutdown complete\n");
|
||||
break;
|
||||
default:
|
||||
|
@ -2575,8 +2619,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
|||
case SND_SOC_DAPM_POST_PMU:
|
||||
flush_work(&dsp->boot_work);
|
||||
|
||||
if (!dsp->booted)
|
||||
return -EIO;
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
if (!dsp->booted) {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = wm_adsp2_ena(dsp);
|
||||
if (ret != 0)
|
||||
|
@ -2594,18 +2642,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
|||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
dsp->running = true;
|
||||
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
if (wm_adsp_fw[dsp->fw].num_caps != 0) {
|
||||
ret = wm_adsp_buffer_init(dsp);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
dsp->running = true;
|
||||
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
|
||||
break;
|
||||
|
@ -2648,16 +2692,23 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
|||
err:
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_event);
|
||||
|
||||
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
|
||||
{
|
||||
dsp->codec = codec;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
char preload[32];
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
|
||||
snd_soc_dapm_disable_pin(dapm, preload);
|
||||
|
||||
wm_adsp2_init_debugfs(dsp, codec);
|
||||
|
||||
dsp->codec = codec;
|
||||
|
||||
return snd_soc_add_codec_controls(codec,
|
||||
&wm_adsp_fw_controls[dsp->num - 1],
|
||||
1);
|
||||
|
|
|
@ -62,6 +62,7 @@ struct wm_adsp {
|
|||
int fw;
|
||||
int fw_ver;
|
||||
|
||||
bool preloaded;
|
||||
bool booted;
|
||||
bool running;
|
||||
|
||||
|
@ -86,7 +87,12 @@ struct wm_adsp {
|
|||
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
|
||||
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
|
||||
|
||||
#define WM_ADSP2_PRELOAD_SWITCH(wname, num) \
|
||||
SOC_SINGLE_EXT(wname " Preload Switch", SND_SOC_NOPM, num, 1, 0, \
|
||||
wm_adsp2_preloader_get, wm_adsp2_preloader_put)
|
||||
|
||||
#define WM_ADSP2(wname, num, event_fn) \
|
||||
SND_SOC_DAPM_SPK(wname " Preload", NULL), \
|
||||
{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \
|
||||
.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
|
||||
|
@ -110,6 +116,11 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
|
|||
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
||||
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
|
||||
int wm_adsp_compr_free(struct snd_compr_stream *stream);
|
||||
int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
|
||||
|
|
|
@ -358,13 +358,20 @@ static struct snd_soc_card evm_soc_card = {
|
|||
static int davinci_evm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match =
|
||||
of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
|
||||
struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
|
||||
const struct of_device_id *match;
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct snd_soc_card_drvdata_davinci *drvdata = NULL;
|
||||
struct clk *mclk;
|
||||
int ret = 0;
|
||||
|
||||
match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dai = (struct snd_soc_dai_link *) match->data;
|
||||
|
||||
evm_soc_card.dai_link = dai;
|
||||
|
||||
dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
|
||||
|
|
|
@ -121,9 +121,14 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
|
|||
irq_valid = true;
|
||||
}
|
||||
|
||||
/* Data available. Record mode not supported in PIO mode */
|
||||
if (isr[i] & ISR_RXDA)
|
||||
/*
|
||||
* Data available. Retrieve samples from FIFO
|
||||
* NOTE: Only two channels supported
|
||||
*/
|
||||
if ((isr[i] & ISR_RXDA) && (i == 0) && dev->use_pio) {
|
||||
dw_pcm_pop_rx(dev);
|
||||
irq_valid = true;
|
||||
}
|
||||
|
||||
/* Error Handling: TX */
|
||||
if (isr[i] & ISR_TXFO) {
|
||||
|
|
|
@ -41,10 +41,33 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
|
|||
return tx_ptr; \
|
||||
}
|
||||
|
||||
#define dw_pcm_rx_fn(sample_bits) \
|
||||
static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \
|
||||
struct snd_pcm_runtime *runtime, unsigned int rx_ptr, \
|
||||
bool *period_elapsed) \
|
||||
{ \
|
||||
u##sample_bits (*p)[2] = (void *)runtime->dma_area; \
|
||||
unsigned int period_pos = rx_ptr % runtime->period_size; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < dev->fifo_th; i++) { \
|
||||
p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \
|
||||
p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \
|
||||
period_pos++; \
|
||||
if (++rx_ptr >= runtime->buffer_size) \
|
||||
rx_ptr = 0; \
|
||||
} \
|
||||
*period_elapsed = period_pos >= runtime->period_size; \
|
||||
return rx_ptr; \
|
||||
}
|
||||
|
||||
dw_pcm_tx_fn(16);
|
||||
dw_pcm_tx_fn(32);
|
||||
dw_pcm_rx_fn(16);
|
||||
dw_pcm_rx_fn(32);
|
||||
|
||||
#undef dw_pcm_tx_fn
|
||||
#undef dw_pcm_rx_fn
|
||||
|
||||
static const struct snd_pcm_hardware dw_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
|
@ -57,6 +80,7 @@ static const struct snd_pcm_hardware dw_pcm_hardware = {
|
|||
.rate_min = 32000,
|
||||
.rate_max = 48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
|
@ -68,27 +92,51 @@ static const struct snd_pcm_hardware dw_pcm_hardware = {
|
|||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
void dw_pcm_push_tx(struct dw_i2s_dev *dev)
|
||||
static void dw_pcm_transfer(struct dw_i2s_dev *dev, bool push)
|
||||
{
|
||||
struct snd_pcm_substream *tx_substream;
|
||||
bool tx_active, period_elapsed;
|
||||
struct snd_pcm_substream *substream;
|
||||
bool active, period_elapsed;
|
||||
|
||||
rcu_read_lock();
|
||||
tx_substream = rcu_dereference(dev->tx_substream);
|
||||
tx_active = tx_substream && snd_pcm_running(tx_substream);
|
||||
if (tx_active) {
|
||||
unsigned int tx_ptr = READ_ONCE(dev->tx_ptr);
|
||||
unsigned int new_tx_ptr = dev->tx_fn(dev, tx_substream->runtime,
|
||||
tx_ptr, &period_elapsed);
|
||||
cmpxchg(&dev->tx_ptr, tx_ptr, new_tx_ptr);
|
||||
if (push)
|
||||
substream = rcu_dereference(dev->tx_substream);
|
||||
else
|
||||
substream = rcu_dereference(dev->rx_substream);
|
||||
active = substream && snd_pcm_running(substream);
|
||||
if (active) {
|
||||
unsigned int ptr;
|
||||
unsigned int new_ptr;
|
||||
|
||||
if (push) {
|
||||
ptr = READ_ONCE(dev->tx_ptr);
|
||||
new_ptr = dev->tx_fn(dev, substream->runtime, ptr,
|
||||
&period_elapsed);
|
||||
cmpxchg(&dev->tx_ptr, ptr, new_ptr);
|
||||
} else {
|
||||
ptr = READ_ONCE(dev->rx_ptr);
|
||||
new_ptr = dev->rx_fn(dev, substream->runtime, ptr,
|
||||
&period_elapsed);
|
||||
cmpxchg(&dev->rx_ptr, ptr, new_ptr);
|
||||
}
|
||||
|
||||
if (period_elapsed)
|
||||
snd_pcm_period_elapsed(tx_substream);
|
||||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void dw_pcm_push_tx(struct dw_i2s_dev *dev)
|
||||
{
|
||||
dw_pcm_transfer(dev, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcm_push_tx);
|
||||
|
||||
void dw_pcm_pop_rx(struct dw_i2s_dev *dev)
|
||||
{
|
||||
dw_pcm_transfer(dev, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcm_pop_rx);
|
||||
|
||||
static int dw_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
@ -126,20 +174,18 @@ static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
switch (params_format(hw_params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
dev->tx_fn = dw_pcm_tx_16;
|
||||
dev->rx_fn = dw_pcm_rx_16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
dev->tx_fn = dw_pcm_tx_32;
|
||||
dev->rx_fn = dw_pcm_rx_32;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev->dev, "invalid format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dev_err(dev->dev, "only playback is available\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
if (ret < 0)
|
||||
|
@ -163,13 +209,21 @@ static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
WRITE_ONCE(dev->tx_ptr, 0);
|
||||
rcu_assign_pointer(dev->tx_substream, substream);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
WRITE_ONCE(dev->tx_ptr, 0);
|
||||
rcu_assign_pointer(dev->tx_substream, substream);
|
||||
} else {
|
||||
WRITE_ONCE(dev->rx_ptr, 0);
|
||||
rcu_assign_pointer(dev->rx_substream, substream);
|
||||
}
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
rcu_assign_pointer(dev->tx_substream, NULL);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
rcu_assign_pointer(dev->tx_substream, NULL);
|
||||
else
|
||||
rcu_assign_pointer(dev->rx_substream, NULL);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -183,7 +237,12 @@ static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
|
|||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct dw_i2s_dev *dev = runtime->private_data;
|
||||
snd_pcm_uframes_t pos = READ_ONCE(dev->tx_ptr);
|
||||
snd_pcm_uframes_t pos;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
pos = READ_ONCE(dev->tx_ptr);
|
||||
else
|
||||
pos = READ_ONCE(dev->rx_ptr);
|
||||
|
||||
return pos < runtime->buffer_size ? pos : 0;
|
||||
}
|
||||
|
|
|
@ -105,20 +105,27 @@ struct dw_i2s_dev {
|
|||
struct i2s_clk_config_data config;
|
||||
int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
|
||||
|
||||
/* data related to PIO transfers (TX) */
|
||||
/* data related to PIO transfers */
|
||||
bool use_pio;
|
||||
struct snd_pcm_substream __rcu *tx_substream;
|
||||
struct snd_pcm_substream __rcu *rx_substream;
|
||||
unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
|
||||
struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
|
||||
bool *period_elapsed);
|
||||
unsigned int (*rx_fn)(struct dw_i2s_dev *dev,
|
||||
struct snd_pcm_runtime *runtime, unsigned int rx_ptr,
|
||||
bool *period_elapsed);
|
||||
unsigned int tx_ptr;
|
||||
unsigned int rx_ptr;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM)
|
||||
void dw_pcm_push_tx(struct dw_i2s_dev *dev);
|
||||
void dw_pcm_pop_rx(struct dw_i2s_dev *dev);
|
||||
int dw_pcm_register(struct platform_device *pdev);
|
||||
#else
|
||||
void dw_pcm_push_tx(struct dw_i2s_dev *dev) { }
|
||||
void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { }
|
||||
int dw_pcm_register(struct platform_device *pdev)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <sound/soc.h>
|
||||
|
||||
#include "mpc5200_dma.h"
|
||||
#include "mpc5200_psc_ac97.h"
|
||||
|
||||
#define DRV_NAME "efika-audio-fabric"
|
||||
|
||||
|
|
|
@ -668,7 +668,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
|
|||
.playback = {
|
||||
.stream_name = "CPU-Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.channels_max = 32,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 192000,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
@ -677,7 +677,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
|
|||
.capture = {
|
||||
.stream_name = "CPU-Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.channels_max = 32,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 192000,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <asm/mpc52xx_psc.h>
|
||||
|
||||
#include "mpc5200_dma.h"
|
||||
#include "mpc5200_psc_ac97.h"
|
||||
|
||||
#define DRV_NAME "mpc5200-psc-ac97"
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Freescale MPC5200 PSC in AC97 mode
|
||||
* ALSA SoC Digital Audio Interface (DAI) driver
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
|
||||
#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
|
||||
|
||||
#define MPC5200_AC97_NORMAL 0
|
||||
#define MPC5200_AC97_SPDIF 1
|
||||
|
||||
#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */
|
|
@ -98,7 +98,8 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
|
||||
|
||||
int asoc_simple_card_parse_clk(struct device_node *node,
|
||||
int asoc_simple_card_parse_clk(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct device_node *dai_of_node,
|
||||
struct asoc_simple_dai *simple_dai)
|
||||
{
|
||||
|
@ -111,14 +112,13 @@ int asoc_simple_card_parse_clk(struct device_node *node,
|
|||
* or "system-clock-frequency = <xxx>"
|
||||
* or device's module clock.
|
||||
*/
|
||||
clk = of_clk_get(node, 0);
|
||||
clk = devm_get_clk_from_child(dev, node, NULL);
|
||||
if (!IS_ERR(clk)) {
|
||||
simple_dai->sysclk = clk_get_rate(clk);
|
||||
simple_dai->clk = clk;
|
||||
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
|
||||
simple_dai->sysclk = val;
|
||||
} else {
|
||||
clk = of_clk_get(dai_of_node, 0);
|
||||
clk = devm_get_clk_from_child(dev, dai_of_node, NULL);
|
||||
if (!IS_ERR(clk))
|
||||
simple_dai->sysclk = clk_get_rate(clk);
|
||||
}
|
||||
|
|
|
@ -278,11 +278,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
|
|||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
||||
ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||
ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_parse_clk_cpu(np, dai_link, dai_props);
|
||||
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -153,7 +153,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = asoc_simple_card_parse_clk_codec(np, dai_link, dai_props);
|
||||
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -123,10 +123,8 @@ static int img_prl_out_hw_params(struct snd_pcm_substream *substream,
|
|||
struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int rate, channels;
|
||||
u32 reg, control_set = 0;
|
||||
snd_pcm_format_t format;
|
||||
|
||||
rate = params_rate(params);
|
||||
format = params_format(params);
|
||||
channels = params_channels(params);
|
||||
|
||||
switch (params_format(params)) {
|
||||
|
|
|
@ -2,7 +2,7 @@ config SND_MFLD_MACHINE
|
|||
tristate "SOC Machine Audio driver for Intel Medfield MID platform"
|
||||
depends on INTEL_SCU_IPC
|
||||
select SND_SOC_SN95031
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_PCI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
|
||||
|
@ -10,7 +10,7 @@ config SND_MFLD_MACHINE
|
|||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SST_MFLD_PLATFORM
|
||||
config SND_SST_ATOM_HIFI2_PLATFORM
|
||||
tristate
|
||||
select SND_SOC_COMPRESS
|
||||
|
||||
|
@ -31,13 +31,10 @@ config SND_SOC_INTEL_SST
|
|||
tristate
|
||||
select SND_SOC_INTEL_SST_ACPI if ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
depends on (X86 || COMPILE_TEST)
|
||||
|
||||
# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from
|
||||
# the reverse selection, each machine driver needs to select
|
||||
# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE
|
||||
config SND_SOC_INTEL_SST_FIRMWARE
|
||||
tristate
|
||||
select DW_DMAC_CORE
|
||||
|
||||
config SND_SOC_INTEL_SST_ACPI
|
||||
tristate
|
||||
|
@ -47,16 +44,18 @@ config SND_SOC_INTEL_SST_MATCH
|
|||
|
||||
config SND_SOC_INTEL_HASWELL
|
||||
tristate
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
|
||||
config SND_SOC_INTEL_BAYTRAIL
|
||||
tristate
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
|
||||
config SND_SOC_INTEL_HASWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
|
||||
depends on DW_DMAC_CORE
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
|
@ -68,7 +67,6 @@ config SND_SOC_INTEL_HASWELL_MACH
|
|||
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_DA7219
|
||||
select SND_SOC_MAX98357A
|
||||
|
@ -84,7 +82,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
|
|||
config SND_SOC_INTEL_BXT_RT298_MACH
|
||||
tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_RT298
|
||||
select SND_SOC_DMIC
|
||||
|
@ -99,9 +96,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH
|
|||
config SND_SOC_INTEL_BYT_RT5640_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
depends on DMADEVICES
|
||||
depends on SND_SST_IPC_ACPI = n
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
|
@ -112,9 +108,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
|
|||
config SND_SOC_INTEL_BYT_MAX98090_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
depends on DMADEVICES
|
||||
depends on SND_SST_IPC_ACPI = n
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
|
@ -123,9 +118,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
|
|||
|
||||
config SND_SOC_INTEL_BDW_RT5677_MACH
|
||||
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
|
||||
depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
|
||||
depends on DW_DMAC_CORE=y
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on X86_INTEL_LPSS && GPIOLIB && I2C
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5677
|
||||
help
|
||||
|
@ -134,10 +128,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
|
|||
|
||||
config SND_SOC_INTEL_BROADWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
|
||||
I2C_DESIGNWARE_PLATFORM
|
||||
depends on DW_DMAC_CORE
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
|
||||
depends on DMADEVICES
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT286
|
||||
help
|
||||
|
@ -150,7 +142,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
|
|||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
select SND_SOC_RT5640
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -163,7 +155,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
|
|||
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
|
||||
depends on X86 && I2C && ACPI
|
||||
select SND_SOC_RT5651
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -176,7 +168,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
|
|||
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT5670
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -189,7 +181,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
|
|||
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
|
||||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_RT5645
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -202,7 +194,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
|
|||
depends on X86_INTEL_LPSS && I2C && ACPI
|
||||
select SND_SOC_MAX98090
|
||||
select SND_SOC_TS3A227E
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_ATOM_HIFI2_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
help
|
||||
|
@ -220,7 +212,6 @@ config SND_SOC_INTEL_SKYLAKE
|
|||
config SND_SOC_INTEL_SKL_RT286_MACH
|
||||
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_RT286
|
||||
select SND_SOC_DMIC
|
||||
|
@ -234,7 +225,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH
|
|||
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_SSM4567
|
||||
|
@ -249,7 +239,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
|||
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
||||
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_MAX98357A
|
||||
|
|
|
@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
|
|||
# Platform Support
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
|
||||
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
|
||||
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
|
||||
|
||||
# Machine support
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
|
||||
sst-mfld-platform-compress.o sst-atom-controls.o
|
||||
snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \
|
||||
sst-mfld-platform-compress.o \
|
||||
sst-atom-controls.o
|
||||
|
||||
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
|
||||
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-soc-sst-atom-hifi2-platform.o
|
||||
|
||||
# DSP driver
|
||||
obj-$(CONFIG_SND_SST_IPC) += sst/
|
||||
|
|
|
@ -801,13 +801,11 @@ static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai,
|
|||
|
||||
switch (format) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
return SSP_FS_ACTIVE_LOW;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
return SSP_FS_ACTIVE_HIGH;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
return SSP_FS_ACTIVE_LOW;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
return SSP_FS_ACTIVE_HIGH;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
return SSP_FS_ACTIVE_LOW;
|
||||
default:
|
||||
dev_err(dai->dev, "Invalid frame sync polarity %d\n", format);
|
||||
}
|
||||
|
@ -1087,8 +1085,8 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
|
|||
SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL),
|
||||
SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL),
|
||||
SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_STEREO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_STEREO, sst_set_media_loop),
|
||||
SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop),
|
||||
|
||||
/* Media Mixers */
|
||||
|
|
|
@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sst_runtime_stream *stream;
|
||||
int ret_val = 0, str_id;
|
||||
int str_id;
|
||||
|
||||
stream = substream->runtime->private_data;
|
||||
power_down_sst(stream);
|
||||
|
||||
str_id = stream->stream_info.str_id;
|
||||
if (str_id)
|
||||
ret_val = stream->ops->close(sst->dev, str_id);
|
||||
stream->ops->close(sst->dev, str_id);
|
||||
module_put(sst->dev->driver->owner);
|
||||
kfree(stream);
|
||||
}
|
||||
|
@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
|
|||
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
|
||||
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:sst-atom-hifi2-platform");
|
||||
MODULE_ALIAS("platform:sst-mfld-platform");
|
||||
|
|
|
@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
|
|||
static unsigned long cht_machine_id;
|
||||
|
||||
#define CHT_SURFACE_MACH 1
|
||||
#define BYT_THINKPAD_10 2
|
||||
|
||||
static int cht_surface_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
|
@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
cht_machine_id = BYT_THINKPAD_10;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const struct dmi_system_id byt_table[] = {
|
||||
{
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct dmi_system_id cht_table[] = {
|
||||
{
|
||||
|
@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = {
|
|||
"10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data };
|
||||
|
||||
static struct sst_acpi_mach byt_thinkpad_10 = {
|
||||
"10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
|
||||
&byt_rvp_platform_data };
|
||||
|
||||
static struct sst_acpi_mach *cht_quirk(void *arg)
|
||||
{
|
||||
struct sst_acpi_mach *mach = arg;
|
||||
|
@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg)
|
|||
return mach;
|
||||
}
|
||||
|
||||
static struct sst_acpi_mach *byt_quirk(void *arg)
|
||||
{
|
||||
struct sst_acpi_mach *mach = arg;
|
||||
|
||||
dmi_check_system(byt_table);
|
||||
|
||||
if (cht_machine_id == BYT_THINKPAD_10)
|
||||
return &byt_thinkpad_10;
|
||||
else
|
||||
return mach;
|
||||
}
|
||||
|
||||
|
||||
static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk,
|
||||
&byt_rvp_platform_data },
|
||||
{"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
|
@ -445,6 +480,12 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
|
|||
&byt_rvp_platform_data },
|
||||
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
/* some Baytrail platforms rely on RT5645, use CHT machine driver */
|
||||
{"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
{"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -458,12 +499,19 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
|||
&chv_platform_data },
|
||||
{"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
{"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
|
||||
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
|
||||
&chv_platform_data },
|
||||
|
||||
{"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL,
|
||||
&chv_platform_data },
|
||||
/* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
|
||||
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL,
|
||||
&chv_platform_data },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
|
|||
u32 data_size, i;
|
||||
void *data_offset;
|
||||
struct stream_info *stream;
|
||||
union ipc_header_high msg_high;
|
||||
u32 msg_low, pipe_id;
|
||||
|
||||
msg_high = msg->mrfld_header.p.header_high;
|
||||
msg_low = msg->mrfld_header.p.header_low_payload;
|
||||
msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
|
||||
data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));
|
||||
|
|
|
@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
{
|
||||
int retval = 0;
|
||||
struct stream_info *str_info;
|
||||
struct intel_sst_ops *ops;
|
||||
|
||||
dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
|
||||
|
||||
|
@ -407,7 +406,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
|
|||
str_info = get_stream_info(sst_drv_ctx, str_id);
|
||||
if (!str_info)
|
||||
return -EINVAL;
|
||||
ops = sst_drv_ctx->ops;
|
||||
|
||||
mutex_lock(&str_info->lock);
|
||||
if (str_info->status != STREAM_UN_INIT) {
|
||||
|
|
|
@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev)
|
|||
{
|
||||
broadwell_rt286.dev = &pdev->dev;
|
||||
|
||||
snd_soc_set_dmi_name(&broadwell_rt286, NULL);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,17 @@
|
|||
#define QUAD_CHANNEL 4
|
||||
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
static struct snd_soc_jack broxton_hdmi[3];
|
||||
|
||||
struct bxt_hdmi_pcm {
|
||||
struct list_head head;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int device;
|
||||
};
|
||||
|
||||
struct bxt_card_private {
|
||||
struct list_head hdmi_pcm_list;
|
||||
};
|
||||
|
||||
enum {
|
||||
BXT_DPCM_AUDIO_PB = 0,
|
||||
|
@ -84,9 +95,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
|
|||
{"codec0_in", NULL, "ssp1 Rx"},
|
||||
{"ssp1 Rx", NULL, "Capture"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
{"HDMI1", NULL, "hif5-0 Output"},
|
||||
{"HDMI2", NULL, "hif6-0 Output"},
|
||||
{"HDMI2", NULL, "hif7-0 Output"},
|
||||
|
||||
{"hifi3", NULL, "iDisp3 Tx"},
|
||||
{"iDisp3 Tx", NULL, "iDisp3_out"},
|
||||
|
@ -147,9 +158,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
|
||||
return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
|
||||
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
|
||||
if (!pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
|
||||
pcm->codec_dai = dai;
|
||||
|
||||
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
|
||||
|
@ -357,7 +379,6 @@ static struct snd_soc_dai_link broxton_dais[] = {
|
|||
.platform_name = "0000:00:0e.0",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.ops = &broxton_refcap_ops,
|
||||
|
@ -497,6 +518,40 @@ static struct snd_soc_dai_link broxton_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int bxt_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
codec = pcm->codec_dai->codec;
|
||||
snprintf(jack_name, sizeof(jack_name),
|
||||
"HDMI/DP, pcm=%d Jack", pcm->device);
|
||||
err = snd_soc_card_jack_new(card, jack_name,
|
||||
SND_JACK_AVOUT, &broxton_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&broxton_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* broxton audio machine driver for SPT + da7219 */
|
||||
static struct snd_soc_card broxton_audio_card = {
|
||||
.name = "bxtda7219max",
|
||||
|
@ -510,11 +565,22 @@ static struct snd_soc_card broxton_audio_card = {
|
|||
.dapm_routes = broxton_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(broxton_map),
|
||||
.fully_routed = true,
|
||||
.late_probe = bxt_card_late_probe,
|
||||
};
|
||||
|
||||
static int broxton_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bxt_card_private *ctx;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
|
||||
|
||||
broxton_audio_card.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&broxton_audio_card, ctx);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,19 @@
|
|||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include "../../codecs/rt298.h"
|
||||
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
/* Headset jack detection DAPM pins */
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
static struct snd_soc_jack broxton_hdmi[3];
|
||||
|
||||
struct bxt_hdmi_pcm {
|
||||
struct list_head head;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int device;
|
||||
};
|
||||
|
||||
struct bxt_rt286_private {
|
||||
struct list_head hdmi_pcm_list;
|
||||
};
|
||||
|
||||
enum {
|
||||
BXT_DPCM_AUDIO_PB = 0,
|
||||
|
@ -82,9 +93,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
|
|||
{"DMIC1 Pin", NULL, "DMIC2"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
{"HDMI1", NULL, "hif5-0 Output"},
|
||||
{"HDMI2", NULL, "hif6-0 Output"},
|
||||
{"HDMI2", NULL, "hif7-0 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp5 Tx"},
|
||||
|
@ -139,9 +150,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
|
||||
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
|
||||
return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
|
||||
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
|
||||
if (!pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
|
||||
pcm->codec_dai = dai;
|
||||
|
||||
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
|
@ -432,6 +454,41 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int bxt_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct bxt_hdmi_pcm *pcm;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
codec = pcm->codec_dai->codec;
|
||||
snprintf(jack_name, sizeof(jack_name),
|
||||
"HDMI/DP, pcm=%d Jack", pcm->device);
|
||||
err = snd_soc_card_jack_new(card, jack_name,
|
||||
SND_JACK_AVOUT, &broxton_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&broxton_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
|
||||
/* broxton audio machine driver for SPT + RT298S */
|
||||
static struct snd_soc_card broxton_rt298 = {
|
||||
.name = "broxton-rt298",
|
||||
|
@ -445,11 +502,22 @@ static struct snd_soc_card broxton_rt298 = {
|
|||
.dapm_routes = broxton_rt298_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
|
||||
.fully_routed = true,
|
||||
.late_probe = bxt_card_late_probe,
|
||||
|
||||
};
|
||||
|
||||
static int broxton_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bxt_rt286_private *ctx;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
|
||||
|
||||
broxton_rt298.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&broxton_rt298, ctx);
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
|
||||
}
|
||||
|
|
|
@ -386,6 +386,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
|||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_SSP0_AIF1),
|
||||
|
||||
},
|
||||
{
|
||||
.callback = byt_rt5640_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
|
||||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_SSP0_AIF1),
|
||||
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
@ -546,7 +556,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
if (ret < 0) {
|
||||
|
@ -572,7 +582,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
if (ret < 0) {
|
||||
|
@ -856,7 +866,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
|
|||
static struct platform_driver snd_byt_rt5640_mc_driver = {
|
||||
.driver = {
|
||||
.name = "bytcr_rt5640",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = snd_byt_rt5640_mc_probe,
|
||||
};
|
||||
|
|
|
@ -185,7 +185,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
|
||||
|
@ -319,7 +319,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
|
|||
static struct platform_driver snd_byt_rt5651_mc_driver = {
|
||||
.driver = {
|
||||
.name = "bytcr_rt5651",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = snd_byt_rt5651_mc_probe,
|
||||
};
|
||||
|
|
|
@ -23,7 +23,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/platform_sst_audio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
@ -33,7 +37,8 @@
|
|||
#include "../common/sst-acpi.h"
|
||||
|
||||
#define CHT_PLAT_CLK_3_HZ 19200000
|
||||
#define CHT_CODEC_DAI "rt5645-aif1"
|
||||
#define CHT_CODEC_DAI1 "rt5645-aif1"
|
||||
#define CHT_CODEC_DAI2 "rt5645-aif2"
|
||||
|
||||
struct cht_acpi_card {
|
||||
char *codec_id;
|
||||
|
@ -45,15 +50,36 @@ struct cht_mc_private {
|
|||
struct snd_soc_jack jack;
|
||||
struct cht_acpi_card *acpi_card;
|
||||
char codec_name[16];
|
||||
struct clk *mclk;
|
||||
};
|
||||
|
||||
#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff)
|
||||
#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */
|
||||
#define CHT_RT5645_SSP0_AIF1 BIT(17)
|
||||
#define CHT_RT5645_SSP0_AIF2 BIT(18)
|
||||
|
||||
static unsigned long cht_rt5645_quirk = 0;
|
||||
|
||||
static void log_quirks(struct device *dev)
|
||||
{
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2)
|
||||
dev_info(dev, "quirk SSP2_AIF2 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1)
|
||||
dev_info(dev, "quirk SSP0_AIF1 enabled");
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)
|
||||
dev_info(dev, "quirk SSP0_AIF2 enabled");
|
||||
}
|
||||
|
||||
static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
list_for_each_entry(rtd, &card->rtd_list, list) {
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
|
||||
strlen(CHT_CODEC_DAI)))
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1,
|
||||
strlen(CHT_CODEC_DAI1)))
|
||||
return rtd->codec_dai;
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI2,
|
||||
strlen(CHT_CODEC_DAI2)))
|
||||
return rtd->codec_dai;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -65,6 +91,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
|||
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
codec_dai = cht_get_codec_dai(card);
|
||||
|
@ -73,19 +100,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (!SND_SOC_DAPM_EVENT_OFF(event))
|
||||
return 0;
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
if (ctx->mclk) {
|
||||
ret = clk_prepare_enable(ctx->mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev,
|
||||
"could not configure MCLK state");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Set codec sysclk source to its internal clock because codec PLL will
|
||||
* be off when idle and MCLK will also be off when codec is
|
||||
* runtime suspended. Codec needs clock for jack detection and button
|
||||
* press. MCLK is turned off with clock framework or ACPI.
|
||||
*/
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
|
||||
48000 * 512, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set codec sysclk source to its internal clock because codec PLL will
|
||||
* be off when idle and MCLK will also be off by ACPI when codec is
|
||||
* runtime suspended. Codec needs clock for jack detection and button
|
||||
* press.
|
||||
*/
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
|
||||
0, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
if (ctx->mclk)
|
||||
clk_disable_unprepare(ctx->mclk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -97,7 +135,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_POST_PMD),
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
|
||||
|
@ -109,12 +147,6 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = {
|
|||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOL"},
|
||||
{"Ext Spk", NULL, "SPOR"},
|
||||
{"AIF1 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx" },
|
||||
{"codec_in1", NULL, "ssp2 Rx" },
|
||||
{"ssp2 Rx", NULL, "AIF1 Capture"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
|
@ -130,16 +162,42 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = {
|
|||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOL"},
|
||||
{"Ext Spk", NULL, "SPOR"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
{"Ext Spk", NULL, "Platform Clock"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = {
|
||||
{"AIF1 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx" },
|
||||
{"codec_in1", NULL, "ssp2 Rx" },
|
||||
{"ssp2 Rx", NULL, "AIF1 Capture"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
{"Ext Spk", NULL, "Platform Clock"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = {
|
||||
{"AIF2 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx" },
|
||||
{"codec_in1", NULL, "ssp2 Rx" },
|
||||
{"ssp2 Rx", NULL, "AIF2 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = {
|
||||
{"AIF1 Playback", NULL, "ssp0 Tx"},
|
||||
{"ssp0 Tx", NULL, "modem_out"},
|
||||
{"modem_in", NULL, "ssp0 Rx" },
|
||||
{"ssp0 Rx", NULL, "AIF1 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = {
|
||||
{"AIF2 Playback", NULL, "ssp0 Tx"},
|
||||
{"ssp0 Tx", NULL, "modem_out"},
|
||||
{"modem_in", NULL, "ssp0 Rx" },
|
||||
{"ssp0 Rx", NULL, "AIF2 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cht_mc_controls[] = {
|
||||
|
@ -185,29 +243,66 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* uncomment when we have a real quirk
|
||||
static int cht_rt5645_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
cht_rt5645_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
static const struct dmi_system_id cht_rt5645_quirk_table[] = {
|
||||
{
|
||||
},
|
||||
};
|
||||
|
||||
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
int jack_type;
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_dai *codec_dai = runtime->codec_dai;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
|
||||
|
||||
/* Select clk_i2s1_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S1_ASRC);
|
||||
|
||||
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
|
||||
return ret;
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
/* Select clk_i2s2_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S2_ASRC);
|
||||
} else {
|
||||
/* Select clk_i2s1_asrc as ASRC clock source */
|
||||
rt5645_sel_asrc_clk_src(codec,
|
||||
RT5645_DA_STEREO_FILTER |
|
||||
RT5645_DA_MONO_L_FILTER |
|
||||
RT5645_DA_MONO_R_FILTER |
|
||||
RT5645_AD_STEREO_FILTER,
|
||||
RT5645_CLK_SEL_I2S1_ASRC);
|
||||
}
|
||||
|
||||
if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp2_aif2_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp2_aif2_map));
|
||||
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp0_aif1_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp0_aif1_map));
|
||||
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp0_aif2_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp0_aif2_map));
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm,
|
||||
cht_rt5645_ssp2_aif1_map,
|
||||
ARRAY_SIZE(cht_rt5645_ssp2_aif1_map));
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650)
|
||||
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
|
@ -225,12 +320,33 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
|||
|
||||
rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack);
|
||||
|
||||
if (ctx->mclk) {
|
||||
/*
|
||||
* The firmware might enable the clock at
|
||||
* boot (this information may or may not
|
||||
* be reflected in the enable clock register).
|
||||
* To change the rate we must disable the clock
|
||||
* first to cover these cases. Due to common
|
||||
* clock framework restrictions that do not allow
|
||||
* to disable a clock that has not been enabled,
|
||||
* we need to enable the clock first.
|
||||
*/
|
||||
ret = clk_prepare_enable(ctx->mclk);
|
||||
if (!ret)
|
||||
clk_disable_unprepare(ctx->mclk);
|
||||
|
||||
ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
|
||||
|
||||
if (ret)
|
||||
dev_err(runtime->dev, "unable to set MCLK rate\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
int ret;
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
|
@ -240,8 +356,67 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* set SSP0 to 16-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot, override config
|
||||
* with explicit setting to I2S 2ch 16-bit. The word length is set with
|
||||
* dai_set_tdm_slot() since there is no other API exposed
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_fmt(rtd->codec_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->codec_dai,
|
||||
SND_SOC_DAIFMT_DSP_B |
|
||||
SND_SOC_DAIFMT_IB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0xF, 0xF, 4, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -303,8 +478,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
|||
.no_pcm = 1,
|
||||
.codec_dai_name = "rt5645-aif1",
|
||||
.codec_name = "i2c-10EC5645:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = cht_codec_init,
|
||||
.be_hw_params_fixup = cht_codec_fixup,
|
||||
.nonatomic = true,
|
||||
|
@ -344,10 +517,31 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
|
|||
static struct cht_acpi_card snd_soc_cards[] = {
|
||||
{"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5648", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC3270", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
|
||||
};
|
||||
|
||||
static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char cht_rt5645_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
|
||||
static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */
|
||||
static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
|
||||
|
||||
static bool is_valleyview(void)
|
||||
{
|
||||
static const struct x86_cpu_id cpu_ids[] = {
|
||||
{ X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
|
||||
{}
|
||||
};
|
||||
|
||||
if (!x86_match_cpu(cpu_ids))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
|
||||
u64 aif_value; /* 1: AIF1, 2: AIF2 */
|
||||
u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */
|
||||
};
|
||||
|
||||
static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -358,22 +552,33 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
struct sst_acpi_mach *mach;
|
||||
const char *i2c_name = NULL;
|
||||
int dai_index = 0;
|
||||
bool found = false;
|
||||
bool is_bytcr = false;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
|
||||
if (!drv)
|
||||
return -ENOMEM;
|
||||
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
|
||||
if (acpi_dev_found(snd_soc_cards[i].codec_id)) {
|
||||
if (acpi_dev_found(snd_soc_cards[i].codec_id) &&
|
||||
(!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"found codec %s\n", snd_soc_cards[i].codec_id);
|
||||
card = snd_soc_cards[i].soc_card;
|
||||
drv->acpi_card = &snd_soc_cards[i];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_err(&pdev->dev, "No matching HID found in supported list\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
mach = card->dev->platform_data;
|
||||
sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
|
||||
|
||||
/* set correct codec name */
|
||||
|
@ -386,9 +591,105 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
/* fixup codec name based on HID */
|
||||
i2c_name = sst_acpi_find_name_from_hid(mach->id);
|
||||
if (i2c_name != NULL) {
|
||||
snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name),
|
||||
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
|
||||
"%s%s", "i2c-", i2c_name);
|
||||
cht_dailink[dai_index].codec_name = cht_rt5640_codec_name;
|
||||
cht_dailink[dai_index].codec_name = cht_rt5645_codec_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* swap SSP0 if bytcr is detected
|
||||
* (will be overridden if DMI quirk is detected)
|
||||
*/
|
||||
if (is_valleyview()) {
|
||||
struct sst_platform_info *p_info = mach->pdata;
|
||||
const struct sst_res_info *res_info = p_info->res_info;
|
||||
|
||||
if (res_info->acpi_ipc_irq_index == 0)
|
||||
is_bytcr = true;
|
||||
}
|
||||
|
||||
if (is_bytcr) {
|
||||
/*
|
||||
* Baytrail CR platforms may have CHAN package in BIOS, try
|
||||
* to find relevant routing quirk based as done on Windows
|
||||
* platforms. We have to read the information directly from the
|
||||
* BIOS, at this stage the card is not created and the links
|
||||
* with the codec driver/pdata are non-existent
|
||||
*/
|
||||
|
||||
struct acpi_chan_package chan_package;
|
||||
|
||||
/* format specified: 2 64-bit integers */
|
||||
struct acpi_buffer format = {sizeof("NN"), "NN"};
|
||||
struct acpi_buffer state = {0, NULL};
|
||||
struct sst_acpi_package_context pkg_ctx;
|
||||
bool pkg_found = false;
|
||||
|
||||
state.length = sizeof(chan_package);
|
||||
state.pointer = &chan_package;
|
||||
|
||||
pkg_ctx.name = "CHAN";
|
||||
pkg_ctx.length = 2;
|
||||
pkg_ctx.format = &format;
|
||||
pkg_ctx.state = &state;
|
||||
pkg_ctx.data_valid = false;
|
||||
|
||||
pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx);
|
||||
if (pkg_found) {
|
||||
if (chan_package.aif_value == 1) {
|
||||
dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF1;
|
||||
} else if (chan_package.aif_value == 2) {
|
||||
dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n");
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
|
||||
} else {
|
||||
dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n");
|
||||
pkg_found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkg_found) {
|
||||
/* no BIOS indications, assume SSP0-AIF2 connection */
|
||||
cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
|
||||
}
|
||||
}
|
||||
|
||||
/* check quirks before creating card */
|
||||
dmi_check_system(cht_rt5645_quirk_table);
|
||||
log_quirks(&pdev->dev);
|
||||
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* fixup codec aif name */
|
||||
snprintf(cht_rt5645_codec_aif_name,
|
||||
sizeof(cht_rt5645_codec_aif_name),
|
||||
"%s", "rt5645-aif2");
|
||||
|
||||
cht_dailink[dai_index].codec_dai_name =
|
||||
cht_rt5645_codec_aif_name;
|
||||
}
|
||||
|
||||
if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
|
||||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
|
||||
|
||||
/* fixup cpu dai name name */
|
||||
snprintf(cht_rt5645_cpu_dai_name,
|
||||
sizeof(cht_rt5645_cpu_dai_name),
|
||||
"%s", "ssp0-port");
|
||||
|
||||
cht_dailink[dai_index].cpu_dai_name =
|
||||
cht_rt5645_cpu_dai_name;
|
||||
}
|
||||
|
||||
if (is_valleyview()) {
|
||||
drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
|
||||
if (IS_ERR(drv->mclk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
|
||||
PTR_ERR(drv->mclk));
|
||||
return PTR_ERR(drv->mclk);
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_card_set_drvdata(card, drv);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -111,8 +112,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
|
|||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Spk", NULL),
|
||||
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("DP", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI", NULL),
|
||||
SND_SOC_DAPM_SPK("DP1", NULL),
|
||||
SND_SOC_DAPM_SPK("DP2", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -130,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
|
|||
{ "MIC", NULL, "Headset Mic" },
|
||||
{ "DMic", NULL, "SoC DMIC" },
|
||||
|
||||
{"HDMI", NULL, "hif5 Output"},
|
||||
{"DP", NULL, "hif6 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "HiFi Playback", NULL, "ssp0 Tx" },
|
||||
{ "ssp0 Tx", NULL, "codec0_out" },
|
||||
|
@ -603,19 +601,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
snprintf(jack_name, sizeof(jack_name),
|
||||
"HDMI/DP, pcm=%d Jack", pcm->device);
|
||||
err = snd_soc_card_jack_new(card, jack_name,
|
||||
SND_JACK_AVOUT,
|
||||
&skylake_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&skylake_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + NAU88L25 */
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -115,8 +116,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
|
|||
SND_SOC_DAPM_SPK("Left Speaker", NULL),
|
||||
SND_SOC_DAPM_SPK("Right Speaker", NULL),
|
||||
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("DP", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI", NULL),
|
||||
SND_SOC_DAPM_SPK("DP1", NULL),
|
||||
SND_SOC_DAPM_SPK("DP2", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
@ -135,8 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
|
|||
{"MIC", NULL, "Headset Mic"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI", NULL, "hif5 Output"},
|
||||
{"DP", NULL, "hif6 Output"},
|
||||
/* CODEC BE connections */
|
||||
{ "Left Playback", NULL, "ssp0 Tx"},
|
||||
{ "Right Playback", NULL, "ssp0 Tx"},
|
||||
|
@ -653,19 +652,39 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
snprintf(jack_name, sizeof(jack_name),
|
||||
"HDMI/DP, pcm=%d Jack", pcm->device);
|
||||
err = snd_soc_card_jack_new(card, jack_name,
|
||||
SND_JACK_AVOUT,
|
||||
&skylake_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&skylake_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + NAU88L25 */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../../codecs/hdac_hdmi.h"
|
||||
|
||||
static struct snd_soc_jack skylake_headset;
|
||||
static struct snd_soc_jack skylake_hdmi[3];
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -94,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
|
|||
{"DMIC1 Pin", NULL, "DMIC2"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp0 Tx"},
|
||||
{ "ssp0 Tx", NULL, "codec0_out"},
|
||||
|
@ -458,19 +455,38 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#define NAME_SIZE 32
|
||||
static int skylake_card_late_probe(struct snd_soc_card *card)
|
||||
{
|
||||
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct skl_hdmi_pcm *pcm;
|
||||
int err;
|
||||
struct snd_soc_codec *codec = NULL;
|
||||
int err, i = 0;
|
||||
char jack_name[NAME_SIZE];
|
||||
|
||||
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
|
||||
codec = pcm->codec_dai->codec;
|
||||
snprintf(jack_name, sizeof(jack_name),
|
||||
"HDMI/DP, pcm=%d Jack", pcm->device);
|
||||
err = snd_soc_card_jack_new(card, jack_name,
|
||||
SND_JACK_AVOUT, &skylake_hdmi[i],
|
||||
NULL, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
|
||||
&skylake_hdmi[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!codec)
|
||||
return -EINVAL;
|
||||
|
||||
return hdac_hdmi_jack_port_init(codec, &card->dapm);
|
||||
}
|
||||
|
||||
/* skylake audio machine driver for SPT + RT286S */
|
||||
|
|
|
@ -252,44 +252,44 @@ void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
|
|||
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
|
||||
|
||||
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
||||
u32 target, u32 timeout, char *operation)
|
||||
u32 target, u32 time, char *operation)
|
||||
{
|
||||
int time, ret;
|
||||
u32 reg;
|
||||
bool done = false;
|
||||
unsigned long timeout;
|
||||
int k = 0, s = 500;
|
||||
|
||||
/*
|
||||
* we will poll for couple of ms using mdelay, if not successful
|
||||
* then go to longer sleep using usleep_range
|
||||
* split the loop into sleeps of varying resolution. more accurately,
|
||||
* the range of wakeups are:
|
||||
* Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
|
||||
* Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
|
||||
* (usleep_range (500, 1000) and usleep_range(5000, 10000) are
|
||||
* both possible in this phase depending on whether k > 10 or not).
|
||||
* Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
|
||||
*/
|
||||
|
||||
/* check if set state successful */
|
||||
for (time = 0; time < 5; time++) {
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
timeout = jiffies + msecs_to_jiffies(time);
|
||||
while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
|
||||
&& time_before(jiffies, timeout)) {
|
||||
k++;
|
||||
if (k > 10)
|
||||
s = 5000;
|
||||
|
||||
if (done == false) {
|
||||
/* sleeping in 10ms steps so adjust timeout value */
|
||||
timeout /= 10;
|
||||
|
||||
for (time = 0; time < timeout; time++) {
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target)
|
||||
break;
|
||||
|
||||
usleep_range(5000, 10000);
|
||||
}
|
||||
usleep_range(s, 2*s);
|
||||
}
|
||||
|
||||
reg = sst_dsp_shim_read_unlocked(ctx, offset);
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
|
||||
(time < timeout) ? "successful" : "timedout");
|
||||
ret = time < timeout ? 0 : -ETIME;
|
||||
|
||||
return ret;
|
||||
if ((reg & mask) == target) {
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
|
||||
reg, operation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n",
|
||||
reg, operation);
|
||||
return -ETIME;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "../common/sst-dsp.h"
|
||||
#include "../common/sst-dsp-priv.h"
|
||||
#include "skl-sst-ipc.h"
|
||||
#include "skl-tplg-interface.h"
|
||||
|
||||
#define BXT_BASEFW_TIMEOUT 3000
|
||||
#define BXT_INIT_TIMEOUT 500
|
||||
|
@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
|
|||
}
|
||||
|
||||
static int
|
||||
bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
||||
bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
|
||||
{
|
||||
struct snd_dma_buffer dmab;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
|
@ -61,11 +60,11 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
int ret = 0, i, dma_id, stream_tag;
|
||||
|
||||
/* library indices start from 1 to N. 0 represents base FW */
|
||||
for (i = 1; i < minfo->lib_count; i++) {
|
||||
ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev);
|
||||
for (i = 1; i < lib_count; i++) {
|
||||
ret = request_firmware(&fw, linfo[i].name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request lib %s failed:%d\n",
|
||||
minfo->lib[i].name, ret);
|
||||
linfo[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -96,7 +95,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
|
||||
minfo->lib[i].name, ret);
|
||||
linfo[i].name, ret);
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
|
||||
ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
|
||||
|
@ -119,8 +118,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo)
|
|||
static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
||||
const void *fwdata, u32 fwsize)
|
||||
{
|
||||
int stream_tag, ret, i;
|
||||
u32 reg;
|
||||
int stream_tag, ret;
|
||||
|
||||
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
|
||||
if (stream_tag <= 0) {
|
||||
|
@ -153,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
}
|
||||
|
||||
/* Step 4: Wait for DONE Bit */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE);
|
||||
|
||||
if (reg & SKL_ADSP_REG_HIPCIE_DONE) {
|
||||
sst_dsp_shim_update_bits_forced(ctx,
|
||||
SKL_ADSP_REG_HIPCIE,
|
||||
ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg);
|
||||
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
BXT_INIT_TIMEOUT, "HIPCIE Done");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timout for Purge Request%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
/* Step 5: power down core1 */
|
||||
|
@ -184,19 +172,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
skl_ipc_op_int_enable(ctx);
|
||||
|
||||
/* Step 7: Wait for ROM init */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
if (SKL_FW_INIT ==
|
||||
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) &
|
||||
SKL_FW_STS_MASK)) {
|
||||
|
||||
dev_info(ctx->dev, "ROM loaded, continue FW loading\n");
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg);
|
||||
ret = -EIO;
|
||||
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
|
||||
SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load");
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
|
@ -432,7 +411,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
|||
int ret;
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
|
||||
struct skl_dfw_manifest *minfo = &skl->manifest;
|
||||
|
||||
if (skl->fw_loaded == false) {
|
||||
skl->boot_complete = false;
|
||||
|
@ -442,8 +420,9 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (minfo->lib_count > 1) {
|
||||
ret = bxt_load_library(ctx, minfo);
|
||||
if (skl->lib_count > 1) {
|
||||
ret = bxt_load_library(ctx, skl->lib_info,
|
||||
skl->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "reload libs failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -640,8 +619,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx)
|
|||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
if (ctx->manifest.lib_count > 1) {
|
||||
ret = sst->fw_ops.load_library(sst, &ctx->manifest);
|
||||
if (ctx->lib_count > 1) {
|
||||
ret = sst->fw_ops.load_library(sst, ctx->lib_info,
|
||||
ctx->lib_count);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load Library failed : %x\n", ret);
|
||||
return ret;
|
||||
|
|
|
@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = {
|
|||
.init_fw = bxt_sst_init_fw,
|
||||
.cleanup = bxt_sst_dsp_cleanup
|
||||
},
|
||||
{
|
||||
.id = 0x3198,
|
||||
.loader_ops = bxt_get_loader_ops,
|
||||
.init = bxt_sst_dsp_init,
|
||||
.init_fw = bxt_sst_init_fw,
|
||||
.cleanup = bxt_sst_dsp_cleanup
|
||||
},
|
||||
};
|
||||
|
||||
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
|
||||
|
|
|
@ -102,14 +102,16 @@ static void dump_config(struct device *dev, u32 instance_id, u8 linktype,
|
|||
}
|
||||
|
||||
static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
|
||||
u32 instance_id, u8 link_type, u8 dirn)
|
||||
u32 instance_id, u8 link_type, u8 dirn, u8 dev_type)
|
||||
{
|
||||
dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n",
|
||||
epnt->virtual_bus_id, epnt->linktype, epnt->direction);
|
||||
dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
|
||||
epnt->virtual_bus_id, epnt->linktype,
|
||||
epnt->direction, epnt->device_type);
|
||||
|
||||
if ((epnt->virtual_bus_id == instance_id) &&
|
||||
(epnt->linktype == link_type) &&
|
||||
(epnt->direction == dirn))
|
||||
(epnt->direction == dirn) &&
|
||||
(epnt->device_type == dev_type))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -117,7 +119,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
|
|||
|
||||
struct nhlt_specific_cfg
|
||||
*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type,
|
||||
u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn)
|
||||
u8 s_fmt, u8 num_ch, u32 s_rate,
|
||||
u8 dirn, u8 dev_type)
|
||||
{
|
||||
struct nhlt_fmt *fmt;
|
||||
struct nhlt_endpoint *epnt;
|
||||
|
@ -135,7 +138,8 @@ struct nhlt_specific_cfg
|
|||
dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
|
||||
|
||||
for (j = 0; j < nhlt->endpoint_count; j++) {
|
||||
if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
|
||||
if (skl_check_ep_match(dev, epnt, instance, link_type,
|
||||
dirn, dev_type)) {
|
||||
fmt = (struct nhlt_fmt *)(epnt->config.caps +
|
||||
epnt->config.size);
|
||||
sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
|
||||
|
@ -189,9 +193,9 @@ int skl_get_dmic_geo(struct skl *skl)
|
|||
return dmic_geo;
|
||||
}
|
||||
|
||||
static void skl_nhlt_trim_space(struct skl *skl)
|
||||
static void skl_nhlt_trim_space(char *trim)
|
||||
{
|
||||
char *s = skl->tplg_name;
|
||||
char *s = trim;
|
||||
int cnt;
|
||||
int i;
|
||||
|
||||
|
@ -218,7 +222,43 @@ int skl_nhlt_update_topology_bin(struct skl *skl)
|
|||
skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
|
||||
nhlt->header.oem_revision, "-tplg.bin");
|
||||
|
||||
skl_nhlt_trim_space(skl);
|
||||
skl_nhlt_trim_space(skl->tplg_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t skl_nhlt_platform_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
|
||||
char platform_id[32];
|
||||
|
||||
sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
|
||||
nhlt->header.oem_id, nhlt->header.oem_table_id,
|
||||
nhlt->header.oem_revision);
|
||||
|
||||
skl_nhlt_trim_space(platform_id);
|
||||
return sprintf(buf, "%s\n", platform_id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL);
|
||||
|
||||
int skl_nhlt_create_sysfs(struct skl *skl)
|
||||
{
|
||||
struct device *dev = &skl->pci->dev;
|
||||
|
||||
if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
|
||||
dev_warn(dev, "Error creating sysfs entry\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void skl_nhlt_remove_sysfs(struct skl *skl)
|
||||
{
|
||||
struct device *dev = &skl->pci->dev;
|
||||
|
||||
sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
|
|||
skl->supend_active--;
|
||||
}
|
||||
|
||||
int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
unsigned int format_val;
|
||||
struct hdac_stream *hstream;
|
||||
struct hdac_ext_stream *stream;
|
||||
int err;
|
||||
|
||||
hstream = snd_hdac_get_stream(bus, params->stream,
|
||||
params->host_dma_id + 1);
|
||||
if (!hstream)
|
||||
return -EINVAL;
|
||||
|
||||
stream = stream_to_hdac_ext_stream(hstream);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 32, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
|
||||
snd_hdac_stream_reset(hdac_stream(stream));
|
||||
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_hdac_stream_setup(hdac_stream(stream));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdac_stream(stream)->prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
unsigned int format_val;
|
||||
struct hdac_stream *hstream;
|
||||
struct hdac_ext_stream *stream;
|
||||
struct hdac_ext_link *link;
|
||||
|
||||
hstream = snd_hdac_get_stream(bus, params->stream,
|
||||
params->link_dma_id + 1);
|
||||
if (!hstream)
|
||||
return -EINVAL;
|
||||
|
||||
stream = stream_to_hdac_ext_stream(hstream);
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
format_val = snd_hdac_calc_stream_format(params->s_freq,
|
||||
params->ch, params->format, 24, 0);
|
||||
|
||||
dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
|
||||
format_val, params->s_freq, params->ch, params->format);
|
||||
|
||||
snd_hdac_ext_link_stream_reset(stream);
|
||||
|
||||
snd_hdac_ext_link_stream_setup(stream, format_val);
|
||||
|
||||
list_for_each_entry(link, &ebus->hlink_list, list) {
|
||||
if (link->index == params->link_index)
|
||||
snd_hdac_ext_link_set_stream_id(link,
|
||||
hstream->stream_tag);
|
||||
}
|
||||
|
||||
stream->link_prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_pcm_open(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -188,32 +262,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_get_format(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct skl_dma_params *dma_params;
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
int format_val = 0;
|
||||
|
||||
if ((ebus_to_hbus(ebus))->ppcap) {
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
format_val = snd_hdac_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
32, 0);
|
||||
} else {
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
|
||||
dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
format_val = dma_params->format;
|
||||
}
|
||||
|
||||
return format_val;
|
||||
}
|
||||
|
||||
static int skl_be_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -234,37 +282,19 @@ static int skl_be_prepare(struct snd_pcm_substream *substream,
|
|||
static int skl_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
unsigned int format_val;
|
||||
int err;
|
||||
struct skl_module_cfg *mconfig;
|
||||
|
||||
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
|
||||
|
||||
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
|
||||
|
||||
format_val = skl_get_format(substream, dai);
|
||||
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
|
||||
hdac_stream(stream)->stream_tag, format_val);
|
||||
snd_hdac_stream_reset(hdac_stream(stream));
|
||||
|
||||
/* In case of XRUN recovery, reset the FW pipe to clean state */
|
||||
if (mconfig && (substream->runtime->status->state ==
|
||||
SNDRV_PCM_STATE_XRUN))
|
||||
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
|
||||
|
||||
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_hdac_stream_setup(hdac_stream(stream));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdac_stream(stream)->prepared = 1;
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
@ -295,6 +325,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
p_params.s_freq = params_rate(params);
|
||||
p_params.host_dma_id = dma_id;
|
||||
p_params.stream = substream->stream;
|
||||
p_params.format = params_format(params);
|
||||
|
||||
m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
|
||||
if (m_cfg)
|
||||
|
@ -438,7 +469,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
if (!w->ignore_suspend) {
|
||||
skl_pcm_prepare(substream, dai);
|
||||
/*
|
||||
* enable DMA Resume enable bit for the stream, set the
|
||||
* dpib & lpib position to resume before starting the
|
||||
|
@ -447,7 +477,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
snd_hdac_ext_stream_drsm_enable(ebus, true,
|
||||
hdac_stream(stream)->index);
|
||||
snd_hdac_ext_stream_set_dpibr(ebus, stream,
|
||||
stream->dpib);
|
||||
stream->lpib);
|
||||
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
|
||||
}
|
||||
|
||||
|
@ -459,7 +489,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
* pipeline is started but there is a delay in starting the
|
||||
* DMA channel on the host.
|
||||
*/
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
ret = skl_decoupled_trigger(substream, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -506,9 +535,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
struct hdac_ext_stream *link_dev;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct hdac_ext_dma_params *dma_params;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct skl_pipe_params p_params = {0};
|
||||
struct hdac_ext_link *link;
|
||||
int stream_tag;
|
||||
|
||||
link_dev = snd_hdac_ext_stream_assign(ebus, substream,
|
||||
HDAC_EXT_STREAM_TYPE_LINK);
|
||||
|
@ -517,16 +547,22 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
|
||||
/* set the stream tag in the codec dai dma params */
|
||||
dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
dma_params->stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
|
||||
|
||||
p_params.s_fmt = snd_pcm_format_width(params_format(params));
|
||||
p_params.ch = params_channels(params);
|
||||
p_params.s_freq = params_rate(params);
|
||||
p_params.stream = substream->stream;
|
||||
p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
|
||||
p_params.link_dma_id = stream_tag - 1;
|
||||
p_params.link_index = link->index;
|
||||
p_params.format = params_format(params);
|
||||
|
||||
return skl_tplg_be_update_params(dai, &p_params);
|
||||
}
|
||||
|
@ -534,41 +570,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
|
||||
struct hdac_ext_stream *link_dev =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
unsigned int format_val = 0;
|
||||
struct skl_dma_params *dma_params;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct hdac_ext_link *link;
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
struct skl_module_cfg *mconfig = NULL;
|
||||
|
||||
dma_params = (struct skl_dma_params *)
|
||||
snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
if (dma_params)
|
||||
format_val = dma_params->format;
|
||||
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
|
||||
hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
snd_hdac_ext_link_stream_reset(link_dev);
|
||||
|
||||
/* In case of XRUN recovery, reset the FW pipe to clean state */
|
||||
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
|
||||
if (mconfig && (substream->runtime->status->state ==
|
||||
SNDRV_PCM_STATE_XRUN))
|
||||
if (mconfig && !mconfig->pipe->passthru &&
|
||||
(substream->runtime->status->state == SNDRV_PCM_STATE_XRUN))
|
||||
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
|
||||
|
||||
snd_hdac_ext_link_stream_setup(link_dev, format_val);
|
||||
|
||||
snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
|
||||
link_dev->link_prepared = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -583,10 +593,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
|
|||
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
skl_link_pcm_prepare(substream, dai);
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
snd_hdac_ext_stream_decouple(ebus, stream, true);
|
||||
snd_hdac_ext_link_stream_start(link_dev);
|
||||
break;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <sound/memalloc.h>
|
||||
#include "skl-sst-cldma.h"
|
||||
#include "skl-tplg-interface.h"
|
||||
#include "skl-topology.h"
|
||||
|
||||
struct sst_dsp;
|
||||
|
@ -145,7 +144,7 @@ struct skl_dsp_fw_ops {
|
|||
int (*load_fw)(struct sst_dsp *ctx);
|
||||
/* FW module parser/loader */
|
||||
int (*load_library)(struct sst_dsp *ctx,
|
||||
struct skl_dfw_manifest *minfo);
|
||||
struct skl_lib_info *linfo, int count);
|
||||
int (*parse_fw)(struct sst_dsp *ctx);
|
||||
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
|
@ -236,5 +235,4 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx,
|
|||
void skl_freeup_uuid_list(struct skl_sst *ctx);
|
||||
|
||||
int skl_dsp_strip_extended_manifest(struct firmware *fw);
|
||||
|
||||
#endif /*__SKL_SST_DSP_H__*/
|
||||
|
|
|
@ -97,8 +97,9 @@ struct skl_sst {
|
|||
/* multi-core */
|
||||
struct skl_dsp_cores cores;
|
||||
|
||||
/* tplg manifest */
|
||||
struct skl_dfw_manifest manifest;
|
||||
/* library info */
|
||||
struct skl_lib_info lib_info[SKL_MAX_LIB];
|
||||
int lib_count;
|
||||
|
||||
/* Callback to update D0i3C register */
|
||||
void (*update_d0i3c)(struct device *dev, bool enable);
|
||||
|
|
|
@ -330,6 +330,31 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
|
|||
multiplier;
|
||||
}
|
||||
|
||||
static u8 skl_tplg_be_dev_type(int dev_type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dev_type) {
|
||||
case SKL_DEVICE_BT:
|
||||
ret = NHLT_DEVICE_BT;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_DMIC:
|
||||
ret = NHLT_DEVICE_DMIC;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_I2S:
|
||||
ret = NHLT_DEVICE_I2S;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = NHLT_DEVICE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
||||
struct skl_sst *ctx)
|
||||
{
|
||||
|
@ -338,6 +363,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
|||
u32 ch, s_freq, s_fmt;
|
||||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl *skl = get_skl_ctx(ctx->dev);
|
||||
u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
|
||||
|
||||
/* check if we already have blob */
|
||||
if (m_cfg->formats_config.caps_size > 0)
|
||||
|
@ -374,7 +400,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
|
|||
|
||||
/* update the blob based on virtual bus_id and default params */
|
||||
cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
|
||||
s_fmt, ch, s_freq, dir);
|
||||
s_fmt, ch, s_freq, dir, dev_type);
|
||||
if (cfg) {
|
||||
m_cfg->formats_config.caps_size = cfg->size;
|
||||
m_cfg->formats_config.caps = (u32 *) &cfg->caps;
|
||||
|
@ -496,6 +522,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
|
||||
struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
|
||||
{
|
||||
switch (mcfg->dev_type) {
|
||||
case SKL_DEVICE_HDAHOST:
|
||||
return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
|
||||
|
||||
case SKL_DEVICE_HDALINK:
|
||||
return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inside a pipe instance, we can have various modules. These modules need
|
||||
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
|
||||
|
@ -535,6 +575,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
|
|||
mconfig->m_state = SKL_MODULE_LOADED;
|
||||
}
|
||||
|
||||
/* prepare the DMA if the module is gateway cpr */
|
||||
ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* update blob if blob is null for be with default value */
|
||||
skl_tplg_update_be_blob(w, ctx);
|
||||
|
||||
|
@ -974,7 +1019,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
|||
struct skl_module_cfg *src_module = NULL, *dst_module;
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_pipe *s_pipe = mconfig->pipe;
|
||||
int ret = 0;
|
||||
|
||||
if (s_pipe->state == SKL_PIPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
@ -996,7 +1040,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
|||
src_module = dst_module;
|
||||
}
|
||||
|
||||
ret = skl_delete_pipe(ctx, mconfig->pipe);
|
||||
skl_delete_pipe(ctx, mconfig->pipe);
|
||||
|
||||
return skl_tplg_unload_pipe_modules(ctx, s_pipe);
|
||||
}
|
||||
|
@ -1207,6 +1251,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
|
|||
switch (mcfg->dev_type) {
|
||||
case SKL_DEVICE_HDALINK:
|
||||
pipe->p_params->link_dma_id = params->link_dma_id;
|
||||
pipe->p_params->link_index = params->link_index;
|
||||
break;
|
||||
|
||||
case SKL_DEVICE_HDAHOST:
|
||||
|
@ -1220,6 +1265,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
|
|||
pipe->p_params->ch = params->ch;
|
||||
pipe->p_params->s_freq = params->s_freq;
|
||||
pipe->p_params->stream = params->stream;
|
||||
pipe->p_params->format = params->format;
|
||||
|
||||
} else {
|
||||
memcpy(pipe->p_params, params, sizeof(*params));
|
||||
|
@ -1428,6 +1474,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
int link_type = skl_tplg_be_link_type(mconfig->dev_type);
|
||||
u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
|
||||
|
||||
skl_tplg_fill_dma_id(mconfig, params);
|
||||
|
||||
|
@ -1437,7 +1484,8 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
/* update the blob based on virtual bus_id*/
|
||||
cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
|
||||
params->s_fmt, params->ch,
|
||||
params->s_freq, params->stream);
|
||||
params->s_freq, params->stream,
|
||||
dev_type);
|
||||
if (cfg) {
|
||||
mconfig->formats_config.caps_size = cfg->size;
|
||||
mconfig->formats_config.caps = (u32 *) &cfg->caps;
|
||||
|
@ -2280,20 +2328,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
|
|||
|
||||
static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_string_elem *str_elem,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0;
|
||||
static int ref_count;
|
||||
|
||||
switch (str_elem->token) {
|
||||
case SKL_TKN_STR_LIB_NAME:
|
||||
if (ref_count > minfo->lib_count - 1) {
|
||||
if (ref_count > skl->skl_sst->lib_count - 1) {
|
||||
ref_count = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(minfo->lib[ref_count].name, str_elem->string,
|
||||
ARRAY_SIZE(minfo->lib[ref_count].name));
|
||||
strncpy(skl->skl_sst->lib_info[ref_count].name,
|
||||
str_elem->string,
|
||||
ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
|
||||
ref_count++;
|
||||
tkn_count++;
|
||||
break;
|
||||
|
@ -2308,14 +2357,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
|
|||
|
||||
static int skl_tplg_get_str_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_array *array,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0, ret;
|
||||
struct snd_soc_tplg_vendor_string_elem *str_elem;
|
||||
|
||||
str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
|
||||
while (tkn_count < array->num_elems) {
|
||||
ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo);
|
||||
ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
|
||||
str_elem++;
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -2329,13 +2378,13 @@ static int skl_tplg_get_str_tkn(struct device *dev,
|
|||
|
||||
static int skl_tplg_get_int_tkn(struct device *dev,
|
||||
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||
struct skl_dfw_manifest *minfo)
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0;
|
||||
|
||||
switch (tkn_elem->token) {
|
||||
case SKL_TKN_U32_LIB_COUNT:
|
||||
minfo->lib_count = tkn_elem->value;
|
||||
skl->skl_sst->lib_count = tkn_elem->value;
|
||||
tkn_count++;
|
||||
break;
|
||||
|
||||
|
@ -2352,7 +2401,7 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
* type.
|
||||
*/
|
||||
static int skl_tplg_get_manifest_tkn(struct device *dev,
|
||||
char *pvt_data, struct skl_dfw_manifest *minfo,
|
||||
char *pvt_data, struct skl *skl,
|
||||
int block_size)
|
||||
{
|
||||
int tkn_count = 0, ret;
|
||||
|
@ -2368,7 +2417,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
off += array->size;
|
||||
switch (array->type) {
|
||||
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
|
||||
ret = skl_tplg_get_str_tkn(dev, array, minfo);
|
||||
ret = skl_tplg_get_str_tkn(dev, array, skl);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -2390,7 +2439,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
|
||||
while (tkn_count <= array->num_elems - 1) {
|
||||
ret = skl_tplg_get_int_tkn(dev,
|
||||
tkn_elem, minfo);
|
||||
tkn_elem, skl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -2411,7 +2460,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
|
|||
* preceded by descriptors for type and size of data block.
|
||||
*/
|
||||
static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
||||
struct device *dev, struct skl_dfw_manifest *minfo)
|
||||
struct device *dev, struct skl *skl)
|
||||
{
|
||||
struct snd_soc_tplg_vendor_array *array;
|
||||
int num_blocks, block_size = 0, block_type, off = 0;
|
||||
|
@ -2454,7 +2503,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
|||
data = (manifest->priv.data + off);
|
||||
|
||||
if (block_type == SKL_TYPE_TUPLE) {
|
||||
ret = skl_tplg_get_manifest_tkn(dev, data, minfo,
|
||||
ret = skl_tplg_get_manifest_tkn(dev, data, skl,
|
||||
block_size);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -2472,27 +2521,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
|
|||
static int skl_manifest_load(struct snd_soc_component *cmpnt,
|
||||
struct snd_soc_tplg_manifest *manifest)
|
||||
{
|
||||
struct skl_dfw_manifest *minfo;
|
||||
struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
int ret = 0;
|
||||
|
||||
/* proceed only if we have private data defined */
|
||||
if (manifest->priv.size == 0)
|
||||
return 0;
|
||||
|
||||
minfo = &skl->skl_sst->manifest;
|
||||
skl_tplg_get_manifest_data(manifest, bus->dev, skl);
|
||||
|
||||
skl_tplg_get_manifest_data(manifest, bus->dev, minfo);
|
||||
|
||||
if (minfo->lib_count > HDA_MAX_LIB) {
|
||||
if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
|
||||
dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
|
||||
minfo->lib_count);
|
||||
ret = -EINVAL;
|
||||
skl->skl_sst->lib_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_tplg_ops skl_tplg_ops = {
|
||||
|
|
|
@ -254,6 +254,8 @@ struct skl_pipe_params {
|
|||
u32 s_freq;
|
||||
u32 s_fmt;
|
||||
u8 linktype;
|
||||
snd_pcm_format_t format;
|
||||
int link_index;
|
||||
int stream;
|
||||
};
|
||||
|
||||
|
@ -332,6 +334,19 @@ struct skl_pipeline {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
#define SKL_LIB_NAME_LENGTH 128
|
||||
#define SKL_MAX_LIB 16
|
||||
|
||||
struct skl_lib_info {
|
||||
char name[SKL_LIB_NAME_LENGTH];
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
struct skl_manifest {
|
||||
u32 lib_count;
|
||||
struct skl_lib_info lib[SKL_MAX_LIB];
|
||||
};
|
||||
|
||||
static inline struct skl *get_skl_ctx(struct device *dev)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
|
@ -383,4 +398,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
|
|||
struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai,
|
||||
int stream);
|
||||
enum skl_bitdepth skl_get_bit_depth(int params);
|
||||
int skl_pcm_host_dma_prepare(struct device *dev,
|
||||
struct skl_pipe_params *params);
|
||||
int skl_pcm_link_dma_prepare(struct device *dev,
|
||||
struct skl_pipe_params *params);
|
||||
#endif
|
||||
|
|
|
@ -157,18 +157,6 @@ struct skl_dfw_algo_data {
|
|||
char params[0];
|
||||
} __packed;
|
||||
|
||||
#define LIB_NAME_LENGTH 128
|
||||
#define HDA_MAX_LIB 16
|
||||
|
||||
struct lib_info {
|
||||
char name[LIB_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
struct skl_dfw_manifest {
|
||||
u32 lib_count;
|
||||
struct lib_info lib[HDA_MAX_LIB];
|
||||
} __packed;
|
||||
|
||||
enum skl_tkn_dir {
|
||||
SKL_DIR_IN,
|
||||
SKL_DIR_OUT
|
||||
|
|
|
@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci,
|
|||
goto out_display_power_off;
|
||||
}
|
||||
|
||||
err = skl_nhlt_create_sysfs(skl);
|
||||
if (err < 0)
|
||||
goto out_nhlt_free;
|
||||
|
||||
skl_nhlt_update_topology_bin(skl);
|
||||
|
||||
pci_set_drvdata(skl->pci, ebus);
|
||||
|
@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci)
|
|||
skl_free_dsp(skl);
|
||||
skl_machine_device_unregister(skl);
|
||||
skl_dmic_device_unregister(skl);
|
||||
skl_nhlt_remove_sysfs(skl);
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
skl_free(ebus);
|
||||
dev_set_drvdata(&pci->dev, NULL);
|
||||
|
@ -878,6 +883,10 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct sst_acpi_mach sst_glk_devdata[] = {
|
||||
{ "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
/* PCI IDs */
|
||||
static const struct pci_device_id skl_ids[] = {
|
||||
/* Sunrise Point-LP */
|
||||
|
@ -889,6 +898,9 @@ static const struct pci_device_id skl_ids[] = {
|
|||
/* KBL */
|
||||
{ PCI_DEVICE(0x8086, 0x9D71),
|
||||
.driver_data = (unsigned long)&sst_kbl_devdata},
|
||||
/* GLK */
|
||||
{ PCI_DEVICE(0x8086, 0x3198),
|
||||
.driver_data = (unsigned long)&sst_glk_devdata},
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, skl_ids);
|
||||
|
|
|
@ -118,7 +118,8 @@ int skl_platform_register(struct device *dev);
|
|||
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev);
|
||||
void skl_nhlt_free(struct nhlt_acpi_table *addr);
|
||||
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
|
||||
u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
|
||||
u8 link_type, u8 s_fmt, u8 no_ch,
|
||||
u32 s_rate, u8 dirn, u8 dev_type);
|
||||
|
||||
int skl_get_dmic_geo(struct skl *skl);
|
||||
int skl_nhlt_update_topology_bin(struct skl *skl);
|
||||
|
@ -130,5 +131,7 @@ int skl_resume_dsp(struct skl *skl);
|
|||
void skl_cleanup_resources(struct skl *skl);
|
||||
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
|
||||
void skl_update_d0i3c(struct device *dev, bool enable);
|
||||
int skl_nhlt_create_sysfs(struct skl *skl);
|
||||
void skl_nhlt_remove_sysfs(struct skl *skl);
|
||||
|
||||
#endif /* __SOUND_SOC_SKL_H */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue