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:
Takashi Iwai 2017-02-20 21:43:40 +01:00
commit 4e25d30c8d
147 changed files with 5469 additions and 1524 deletions

View File

@ -24,6 +24,8 @@ Optional properties:
this parameter to choose where the clock from. this parameter to choose where the clock from.
- By default the clock is from TK pin, if the clock from RK pin, this - By default the clock is from TK pin, if the clock from RK pin, this
property is needed. property is needed.
- #sound-dai-cells: Should contain <0>.
- This property makes the SSC into an automatically registered DAI.
Examples: Examples:
- PDC transfer: - PDC transfer:

View File

@ -2,8 +2,7 @@ Devicetree bindings for the Axentia TSE-850 audio complex
Required properties: Required properties:
- compatible: "axentia,tse850-pcm5142" - compatible: "axentia,tse850-pcm5142"
- axentia,ssc-controller: The phandle of the atmel SSC controller used as - axentia,cpu-dai: The phandle of the cpu dai.
cpu dai.
- axentia,audio-codec: The phandle of the PCM5142 codec. - axentia,audio-codec: The phandle of the PCM5142 codec.
- axentia,add-gpios: gpio specifier that controls the mixer. - axentia,add-gpios: gpio specifier that controls the mixer.
- axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1. - axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1.
@ -43,6 +42,12 @@ the PCM5142 codec.
Example: Example:
&ssc0 {
#sound-dai-cells = <0>;
status = "okay";
};
&i2c { &i2c {
codec: pcm5142@4c { codec: pcm5142@4c {
compatible = "ti,pcm5142"; compatible = "ti,pcm5142";
@ -77,7 +82,7 @@ Example:
sound { sound {
compatible = "axentia,tse850-pcm5142"; compatible = "axentia,tse850-pcm5142";
axentia,ssc-controller = <&ssc0>; axentia,cpu-dai = <&ssc0>;
axentia,audio-codec = <&codec>; axentia,audio-codec = <&codec>;
axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>; axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>;

View File

@ -4,7 +4,7 @@ This device supports both I2C and SPI.
Required properties: 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 - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
- AVDD-supply : Regulator providing analog supply voltage 3.3V - AVDD-supply : Regulator providing analog supply voltage 3.3V
- PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V

View File

@ -4,6 +4,7 @@ Required properties:
- compatible = "mediatek,mt2701-audio"; - compatible = "mediatek,mt2701-audio";
- reg: register location and size - reg: register location and size
- interrupts: Should contain AFE interrupt - interrupts: Should contain AFE interrupt
- power-domains: should define the power domain
- clock-names: should have these clock names: - clock-names: should have these clock names:
"infra_sys_audio_clk", "infra_sys_audio_clk",
"top_audio_mux1_sel", "top_audio_mux1_sel",
@ -58,6 +59,7 @@ Example:
<0 0x112A0000 0 0x20000>; <0 0x112A0000 0 0x20000>;
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>, interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
<GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>; <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
clocks = <&infracfg CLK_INFRA_AUDIO>, clocks = <&infracfg CLK_INFRA_AUDIO>,
<&topckgen CLK_TOP_AUD_MUX1_SEL>, <&topckgen CLK_TOP_AUD_MUX1_SEL>,
<&topckgen CLK_TOP_AUD_MUX2_SEL>, <&topckgen CLK_TOP_AUD_MUX2_SEL>,

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -7,6 +7,7 @@ Required properties:
- compatible: should be one of the followings - compatible: should be one of the followings
- "allwinner,sun4i-a10-i2s" - "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: should contain the I2S interrupt. - interrupts: should contain the I2S interrupt.
@ -19,6 +20,10 @@ Required properties:
- "mod" : module clock for the I2S controller - "mod" : module clock for the I2S controller
- #sound-dai-cells : Must be equal to 0 - #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: Example:
i2s0: i2s@01c22400 { i2s0: i2s@01c22400 {

View File

@ -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";
};
};

View File

@ -10,6 +10,7 @@ Required properties:
- compatible : should be one of the following: - compatible : should be one of the following:
- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
- "allwinner,sun6i-a31-spdif": for the Allwinner A31 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. - reg : Offset and length of the register set for the device.

View File

@ -1,10 +1,12 @@
ZTE ZX296702 I2S controller ZTE ZX296702 I2S controller
Required properties: 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 - reg : Must contain I2S core's registers location and length
- clocks : Pairs of phandle and specifier referencing the controller's clocks. - 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 - dmas: Pairs of phandle and specifier for the DMA channel that is used by
the core. The core expects two dma channels for transmit. the core. The core expects two dma channels for transmit.
- dma-names : Must be "tx" and "rx" - dma-names : Must be "tx" and "rx"
@ -16,12 +18,12 @@ please check:
* dma/dma.txt * dma/dma.txt
Example: Example:
i2s0: i2s0@0b005000 { i2s0: i2s@b005000 {
#sound-dai-cells = <0>; #sound-dai-cells = <0>;
compatible = "zte,zx296702-i2s"; compatible = "zte,zx296718-i2s", "zte,zx296702-i2s";
reg = <0x0b005000 0x1000>; reg = <0x0b005000 0x1000>;
clocks = <&lsp0clk ZX296702_I2S0_DIV>; clocks = <&audiocrm AUDIO_I2S0_WCLK>, <&audiocrm AUDIO_I2S0_PCLK>;
clock-names = "tx"; clock-names = "wclk", "pclk";
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma 5>, <&dma 6>; dmas = <&dma 5>, <&dma 6>;
dma-names = "tx", "rx"; dma-names = "tx", "rx";

View File

@ -106,9 +106,7 @@ static struct s3c_audio_pdata i2sv4_pdata = {
.dma_playback = DMACH_HSI_I2SV40_TX, .dma_playback = DMACH_HSI_I2SV40_TX,
.dma_capture = DMACH_HSI_I2SV40_RX, .dma_capture = DMACH_HSI_I2SV40_RX,
.type = { .type = {
.i2s = { .quirks = QUIRK_PRI_6CHAN,
.quirks = QUIRK_PRI_6CHAN,
},
}, },
}; };

View File

@ -20,6 +20,8 @@
#include <linux/of.h> #include <linux/of.h>
#include "../../sound/soc/atmel/atmel_ssc_dai.h"
/* Serialize access to ssc_list and user count */ /* Serialize access to ssc_list and user count */
static DEFINE_SPINLOCK(user_lock); static DEFINE_SPINLOCK(user_lock);
static LIST_HEAD(ssc_list); 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; 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) static int ssc_probe(struct platform_device *pdev)
{ {
struct resource *regs; 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", dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
ssc->regs, ssc->irq); ssc->regs, ssc->irq);
if (ssc_sound_dai_probe(ssc))
dev_err(&pdev->dev, "failed to auto-setup ssc for audio\n");
return 0; return 0;
} }
@ -211,6 +259,8 @@ static int ssc_remove(struct platform_device *pdev)
{ {
struct ssc_device *ssc = platform_get_drvdata(pdev); struct ssc_device *ssc = platform_get_drvdata(pdev);
ssc_sound_dai_remove(ssc);
spin_lock(&user_lock); spin_lock(&user_lock);
list_del(&ssc->list); list_del(&ssc->list);
spin_unlock(&user_lock); spin_unlock(&user_lock);

View File

@ -248,6 +248,7 @@ struct detailed_timing {
# define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */ # define DRM_ELD_AUD_SYNCH_DELAY_MAX 0xfa /* 500 ms */
#define DRM_ELD_SPEAKER 7 #define DRM_ELD_SPEAKER 7
# define DRM_ELD_SPEAKER_MASK 0x7f
# define DRM_ELD_SPEAKER_RLRC (1 << 6) # define DRM_ELD_SPEAKER_RLRC (1 << 6)
# define DRM_ELD_SPEAKER_FLRC (1 << 5) # define DRM_ELD_SPEAKER_FLRC (1 << 5)
# define DRM_ELD_SPEAKER_RC (1 << 4) # 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; 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 * drm_eld_get_conn_type - Get device type hdmi/dp connected
* @eld: pointer to an ELD memory structure * @eld: pointer to an ELD memory structure

View File

@ -20,6 +20,7 @@ struct ssc_device {
int user; int user;
int irq; int irq;
bool clk_from_rk_pin; bool clk_from_rk_pin;
bool sound_dai;
}; };
struct ssc_device * __must_check ssc_request(unsigned int ssc_num); struct ssc_device * __must_check ssc_request(unsigned int ssc_num);

View File

@ -18,7 +18,7 @@
extern void s3c64xx_ac97_setup_gpio(int); extern void s3c64xx_ac97_setup_gpio(int);
struct samsung_i2s { struct samsung_i2s_type {
/* If the Primary DAI has 5.1 Channels */ /* If the Primary DAI has 5.1 Channels */
#define QUIRK_PRI_6CHAN (1 << 0) #define QUIRK_PRI_6CHAN (1 << 0)
/* If the I2S block has a Stereo Overlay Channel */ /* If the I2S block has a Stereo Overlay Channel */
@ -47,7 +47,5 @@ struct s3c_audio_pdata {
void *dma_capture; void *dma_capture;
void *dma_play_sec; void *dma_play_sec;
void *dma_capture_mic; void *dma_capture_mic;
union { struct samsung_i2s_type type;
struct samsung_i2s i2s;
} type;
}; };

View File

@ -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. * @slave_id: Slave requester id for the DMA channel.
* @filter_data: Custom DMA channel filter data, this will usually be used when * @filter_data: Custom DMA channel filter data, this will usually be used when
* requesting the DMA channel. * 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 * @fifo_size: FIFO size of the DAI controller in bytes
* @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now * @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; u32 maxburst;
unsigned int slave_id; unsigned int slave_id;
void *filter_data; void *filter_data;
const char *chan_name;
unsigned int fifo_size; unsigned int fifo_size;
unsigned int flags; unsigned int flags;
}; };
@ -105,6 +107,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
* playback. * playback.
*/ */
#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) #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 * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM

View File

@ -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, int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
char *prefix); char *prefix);
#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai) \ #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(node, dai_link->cpu_of_node, simple_dai) asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai)
#define asoc_simple_card_parse_clk_codec(node, dai_link, simple_dai) \ #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_card_parse_clk(node, dai_link->codec_of_node, simple_dai) asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai)
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 device_node *dai_of_node,
struct asoc_simple_dai *simple_dai); struct asoc_simple_dai *simple_dai);

View File

@ -256,6 +256,9 @@ struct snd_soc_dai_driver {
int (*resume)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai);
/* compress dai */ /* compress dai */
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); 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 */ /* DAI is also used for the control bus */
bool bus_control; bool bus_control;

View File

@ -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, int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
unsigned int dai_fmt); 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 */ /* 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_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); 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, int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw); 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, int soc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai); struct snd_soc_dai *dai);
@ -785,6 +784,10 @@ struct snd_soc_component_driver {
int (*suspend)(struct snd_soc_component *); int (*suspend)(struct snd_soc_component *);
int (*resume)(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 */ /* DT */
int (*of_xlate_dai_name)(struct snd_soc_component *component, int (*of_xlate_dai_name)(struct snd_soc_component *component,
struct of_phandle_args *args, struct of_phandle_args *args,
@ -859,6 +862,8 @@ struct snd_soc_component {
void (*remove)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *);
int (*suspend)(struct snd_soc_component *); int (*suspend)(struct snd_soc_component *);
int (*resume)(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 */ /* machine specific init */
int (*init)(struct snd_soc_component *component); int (*init)(struct snd_soc_component *component);
@ -941,20 +946,11 @@ struct snd_soc_platform_driver {
int (*pcm_new)(struct snd_soc_pcm_runtime *); int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *); 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 */ /* platform stream pcm ops */
const struct snd_pcm_ops *ops; const struct snd_pcm_ops *ops;
/* platform stream compress ops */ /* platform stream compress ops */
const struct snd_compr_ops *compr_ops; const struct snd_compr_ops *compr_ops;
int (*bespoke_trigger)(struct snd_pcm_substream *, int);
}; };
struct snd_soc_dai_link_component { struct snd_soc_dai_link_component {
@ -1099,6 +1095,8 @@ struct snd_soc_card {
const char *name; const char *name;
const char *long_name; const char *long_name;
const char *driver_name; const char *driver_name;
char dmi_longname[80];
struct device *dev; struct device *dev;
struct snd_card *snd_card; struct snd_card *snd_card;
struct module *owner; struct module *owner;
@ -1647,37 +1645,21 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
int snd_soc_util_init(void); int snd_soc_util_init(void);
void snd_soc_util_exit(void); void snd_soc_util_exit(void);
#define snd_soc_of_parse_card_name(card, propname) \ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
snd_soc_of_parse_card_name_from_node(card, NULL, propname) const char *propname);
int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
struct device_node *np, const char *propname);
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_tdm_slot(struct device_node *np, int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *tx_mask, unsigned int *tx_mask,
unsigned int *rx_mask, unsigned int *rx_mask,
unsigned int *slots, unsigned int *slots,
unsigned int *slot_width); unsigned int *slot_width);
#define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
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,
struct snd_soc_codec_conf *codec_conf, struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node, struct device_node *of_node,
const char *propname); const char *propname);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
#define snd_soc_of_parse_audio_routing(card, propname) \ const char *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);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np, unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix, const char *prefix,
struct device_node **bitclkmaster, struct device_node **bitclkmaster,

View File

@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
{ {
struct hdac_stream *hstream = &stream->hstream; struct hdac_stream *hstream = &stream->hstream;
struct hdac_bus *bus = &ebus->bus; struct hdac_bus *bus = &ebus->bus;
u32 val;
int mask = AZX_PPCTL_PROCEN(hstream->index);
spin_lock_irq(&bus->reg_lock); spin_lock_irq(&bus->reg_lock);
if (decouple) val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
AZX_PPCTL_PROCEN(hstream->index)); if (decouple && !val)
else snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, else if (!decouple && val)
AZX_PPCTL_PROCEN(hstream->index), 0); snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
stream->decoupled = decouple; stream->decoupled = decouple;
spin_unlock_irq(&bus->reg_lock); spin_unlock_irq(&bus->reg_lock);
} }

View File

@ -670,13 +670,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
{ {
int status; int status;
uint64_t size; uint64_t size;
struct snd_dma_buffer *dma_buffer;
struct page *pg; struct page *pg;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd; struct audio_substream_data *rtd;
dma_buffer = &substream->dma_buffer;
runtime = substream->runtime; runtime = substream->runtime;
rtd = runtime->private_data; rtd = runtime->private_data;

View File

@ -51,11 +51,7 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "atmel_ssc_dai.h"
struct tse850_priv { struct tse850_priv {
int ssc_id;
struct gpio_desc *add; struct gpio_desc *add;
struct gpio_desc *loop1; struct gpio_desc *loop1;
struct gpio_desc *loop2; 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 *np = pdev->dev.of_node;
struct device_node *codec_np, *cpu_np; struct device_node *codec_np, *cpu_np;
struct snd_soc_card *card = &tse850_card;
struct snd_soc_dai_link *dailink = &tse850_dailink; struct snd_soc_dai_link *dailink = &tse850_dailink;
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
if (!np) { if (!np) {
dev_err(&pdev->dev, "only device tree supported\n"); dev_err(&pdev->dev, "only device tree supported\n");
return -EINVAL; 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) { 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; return -EINVAL;
} }
dailink->cpu_of_node = cpu_np; dailink->cpu_of_node = cpu_np;
dailink->platform_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); of_node_put(cpu_np);
codec_np = of_parse_phandle(np, "axentia,audio-codec", 0); codec_np = of_parse_phandle(np, "axentia,audio-codec", 0);
@ -415,23 +408,14 @@ static int tse850_probe(struct platform_device *pdev)
return ret; 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); ret = snd_soc_register_card(card);
if (ret) { if (ret) {
dev_err(dev, "snd_soc_register_card failed\n"); dev_err(dev, "snd_soc_register_card failed\n");
goto err_put_audio; goto err_disable_ana;
} }
return 0; return 0;
err_put_audio:
atmel_ssc_put_audio(tse850->ssc_id);
err_disable_ana: err_disable_ana:
regulator_disable(tse850->ana); regulator_disable(tse850->ana);
return ret; return ret;
@ -443,7 +427,6 @@ static int tse850_remove(struct platform_device *pdev)
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card); snd_soc_unregister_card(card);
atmel_ssc_put_audio(tse850->ssc_id);
regulator_disable(tse850->ana); regulator_disable(tse850->ana);
return 0; return 0;

View File

@ -45,7 +45,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C select SND_SOC_ALC5632 if I2C
select SND_SOC_BT_SCO 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_CS35L32 if I2C
select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L33 if I2C
select SND_SOC_CS35L34 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_MAX9877 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8825 if I2C select SND_SOC_NAU8825 if I2C
select SND_SOC_HDMI_CODEC select SND_SOC_HDMI_CODEC
@ -117,8 +118,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5651 if I2C select SND_SOC_RT5651 if I2C
select SND_SOC_RT5659 if I2C select SND_SOC_RT5659 if I2C
select SND_SOC_RT5660 if I2C select SND_SOC_RT5660 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5663 if I2C select SND_SOC_RT5663 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5670 if I2C select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C select SND_SOC_SGTL5000 if I2C
@ -525,14 +526,16 @@ config SND_SOC_HDMI_CODEC
select HDMI select HDMI
config SND_SOC_ES8328 config SND_SOC_ES8328
tristate "Everest Semi ES8328 CODEC" tristate
config SND_SOC_ES8328_I2C config SND_SOC_ES8328_I2C
tristate tristate "Everest Semi ES8328 CODEC (I2C)"
depends on I2C
select SND_SOC_ES8328 select SND_SOC_ES8328
config SND_SOC_ES8328_SPI config SND_SOC_ES8328_SPI
tristate tristate "Everest Semi ES8328 CODEC (SPI)"
depends on SPI_MASTER
select SND_SOC_ES8328 select SND_SOC_ES8328
config SND_SOC_GTM601 config SND_SOC_GTM601
@ -668,8 +671,8 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5651=y default y if SND_SOC_RT5651=y
default y if SND_SOC_RT5659=y default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5660=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_RT5663=y
default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5670=y default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y default y if SND_SOC_RT5677=y
default m if SND_SOC_RT5514=m 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_RT5651=m
default m if SND_SOC_RT5659=m default m if SND_SOC_RT5659=m
default m if SND_SOC_RT5660=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_RT5663=m
default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5670=m default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m default m if SND_SOC_RT5677=m
@ -728,10 +731,10 @@ config SND_SOC_RT5659
config SND_SOC_RT5660 config SND_SOC_RT5660
tristate tristate
config SND_SOC_RT5665 config SND_SOC_RT5663
tristate tristate
config SND_SOC_RT5663 config SND_SOC_RT5665
tristate tristate
config SND_SOC_RT5670 config SND_SOC_RT5670
@ -1105,6 +1108,10 @@ config SND_SOC_MC13783
config SND_SOC_ML26124 config SND_SOC_ML26124
tristate tristate
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C
config SND_SOC_NAU8810 config SND_SOC_NAU8810
tristate "Nuvoton Technology Corporation NAU88C10 CODEC" tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
depends on I2C depends on I2C

View File

@ -90,6 +90,7 @@ snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o snd-soc-ml26124-objs := ml26124.o
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8825-objs := nau8825.o snd-soc-nau8825-objs := nau8825.o
snd-soc-hdmi-codec-objs := hdmi-codec.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-rt5651-objs := rt5651.o
snd-soc-rt5659-objs := rt5659.o snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5660-objs := rt5660.o snd-soc-rt5660-objs := rt5660.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5663-objs := rt5663.o snd-soc-rt5663-objs := rt5663.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5670-objs := rt5670.o snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.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_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.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_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_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.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_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.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_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_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o

View File

@ -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 snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec); struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {
adau->pll_regs[5] = 1; 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. */ /* 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)); adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {

View File

@ -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_PMU:
case SND_SOC_DAPM_POST_PMD: case SND_SOC_DAPM_POST_PMD:
/* Power save mode OFF */ /* Power save mode OFF */
mdelay(300); msleep(300);
snd_soc_update_bits(codec, SG_SL2, LOPS, 0); snd_soc_update_bits(codec, SG_SL2, LOPS, 0);
break; break;
} }

View File

@ -192,6 +192,7 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_DSP_ROUTES(name) \ #define ARIZONA_DSP_ROUTES(name) \
{ name, NULL, name " Preloader"}, \ { name, NULL, name " Preloader"}, \
{ name " Preloader", NULL, "SYSCLK" }, \ { name " Preloader", NULL, "SYSCLK" }, \
{ name " Preload", NULL, name " Preloader"}, \
{ name, NULL, name " Aux 1" }, \ { name, NULL, name " Aux 1" }, \
{ name, NULL, name " Aux 2" }, \ { name, NULL, name " Aux 2" }, \
{ name, NULL, name " Aux 3" }, \ { name, NULL, name " Aux 3" }, \

View File

@ -173,6 +173,9 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), 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("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_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; 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_gpio(codec);
arizona_init_mono(codec); arizona_init_mono(codec);
arizona_init_notifiers(codec); arizona_init_notifiers(codec);

View File

@ -1634,7 +1634,8 @@ static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* DAI */ /* 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), SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
/* Output Mixers */ /* Output Mixers */

View File

@ -20,12 +20,14 @@
static const struct i2c_device_id es8328_id[] = { static const struct i2c_device_id es8328_id[] = {
{ "es8328", 0 }, { "es8328", 0 },
{ "es8388", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, es8328_id); MODULE_DEVICE_TABLE(i2c, es8328_id);
static const struct of_device_id es8328_of_match[] = { static const struct of_device_id es8328_of_match[] = {
{ .compatible = "everest,es8328", }, { .compatible = "everest,es8328", },
{ .compatible = "everest,es8388", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, es8328_of_match); MODULE_DEVICE_TABLE(of, es8328_of_match);

View File

@ -589,9 +589,21 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
u8 dac_mode = 0; u8 dac_mode = 0;
u8 adc_mode = 0; u8 adc_mode = 0;
/* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) 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; return -EINVAL;
}
/* interface format */ /* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 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, snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode); 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; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
#ifndef __HDAC_HDMI_H__ #ifndef __HDAC_HDMI_H__
#define __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__ */ #endif /* __HDAC_HDMI_H__ */

View File

@ -18,6 +18,7 @@
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/pcm_drm_eld.h> #include <sound/pcm_drm_eld.h>
#include <sound/hdmi-codec.h> #include <sound/hdmi-codec.h>
#include <sound/pcm_iec958.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) #define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list)
LIST_HEAD(hdmi_device_list); LIST_HEAD(hdmi_device_list);
static DEFINE_MUTEX(hdmi_mutex);
#define DAI_NAME_SIZE 16 #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_priv {
struct hdmi_codec_pdata hcd; struct hdmi_codec_pdata hcd;
struct snd_soc_dai_driver *daidrv; struct snd_soc_dai_driver *daidrv;
@ -41,6 +295,8 @@ struct hdmi_codec_priv {
struct snd_pcm_substream *current_stream; struct snd_pcm_substream *current_stream;
struct snd_pcm_hw_constraint_list ratec; struct snd_pcm_hw_constraint_list ratec;
uint8_t eld[MAX_ELD_BYTES]; uint8_t eld[MAX_ELD_BYTES];
struct snd_pcm_chmap *chmap_info;
unsigned int chmap_idx;
}; };
static const struct snd_soc_dapm_widget hdmi_widgets[] = { 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; 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[] = { static const struct snd_kcontrol_new hdmi_controls[] = {
{ {
.access = SNDRV_CTL_ELEM_ACCESS_READ | .access = SNDRV_CTL_ELEM_ACCESS_READ |
@ -140,6 +473,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (ret) if (ret)
return ret; return ret;
} }
/* Select chmap supported */
hdmi_codec_eld_chmap(hcp);
} }
return 0; return 0;
} }
@ -153,6 +488,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
WARN_ON(hcp->current_stream != 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); hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
mutex_lock(&hcp->current_stream_lock); mutex_lock(&hcp->current_stream_lock);
@ -173,7 +509,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
.dig_subframe = { 0 }, .dig_subframe = { 0 },
} }
}; };
int ret; int ret, idx;
dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
params_width(params), params_rate(params), 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_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_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_width = params_width(params);
hp.sample_rate = params_rate(params); hp.sample_rate = params_rate(params);
hp.channels = params_channels(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_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_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 = { static struct snd_soc_dai_driver hdmi_i2s_dai = {
.id = DAI_ID_I2S, .id = DAI_ID_I2S,
.playback = { .playback = {
@ -339,6 +712,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
.sig_bits = 24, .sig_bits = 24,
}, },
.ops = &hdmi_dai_ops, .ops = &hdmi_dai_ops,
.pcm_new = hdmi_codec_pcm_new,
}; };
static const struct snd_soc_dai_driver hdmi_spdif_dai = { 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, .formats = SPDIF_FORMATS,
}, },
.ops = &hdmi_dai_ops, .ops = &hdmi_dai_ops,
.pcm_new = hdmi_codec_pcm_new,
}; };
static char hdmi_dai_name[][DAI_NAME_SIZE] = { static char hdmi_dai_name[][DAI_NAME_SIZE] = {
@ -420,6 +795,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
hd = NULL; hd = NULL;
mutex_lock(&hdmi_mutex);
list_for_each(pos, &hdmi_device_list) { list_for_each(pos, &hdmi_device_list) {
struct hdmi_device *tmp = pos_to_hdmi_device(pos); struct hdmi_device *tmp = pos_to_hdmi_device(pos);
@ -431,13 +807,16 @@ static int hdmi_codec_probe(struct platform_device *pdev)
if (!hd) { if (!hd) {
hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL); hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
if (!hd) if (!hd) {
mutex_unlock(&hdmi_mutex);
return -ENOMEM; return -ENOMEM;
}
hd->dev = dev->parent; hd->dev = dev->parent;
list_add_tail(&hd->list, &hdmi_device_list); list_add_tail(&hd->list, &hdmi_device_list);
} }
mutex_unlock(&hdmi_mutex);
if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) { if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
dev_err(dev, "too many hdmi codec are deteced\n"); 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) 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; return 0;
} }

View File

@ -2456,7 +2456,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
if (err) { if (err) {
micbias = M98090_MBVSEL_2V8; micbias = M98090_MBVSEL_2V8;
dev_info(codec->dev, "use default 2.8v micbias\n"); 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); dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
micbias = M98090_MBVSEL_2V8; micbias = M98090_MBVSEL_2V8;
} }

View File

@ -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 snd_soc_codec *codec = codec_dai->codec;
struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
u8 iface1A = 0, iface1B = 0; u8 iface1A = 0, iface1B = 0;
int ret;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFM:
@ -346,8 +345,8 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
ret = regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
ret = regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
return 0; return 0;
} }

835
sound/soc/codecs/nau8540.c Normal file
View File

@ -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");

222
sound/soc/codecs/nau8540.h Normal file
View File

@ -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__ */

View File

@ -1231,7 +1231,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(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); 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); 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)) { switch (params_width(params)) {
case 16: case 16:
val_len |= NAU8825_I2S_DL_16; val_len |= NAU8825_I2S_DL_16;

View File

@ -402,10 +402,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
u32 val, mask, shift, reg; u32 val, mask, shift, reg;
unsigned int rate, fmt, ratio, max_ratio; unsigned int rate, fmt, ratio, max_ratio;
int i, min_frame_size; int i, min_frame_size;
snd_pcm_format_t format;
rate = params_rate(params); rate = params_rate(params);
format = params_format(params);
ratio = pcm3168a->sysclk / rate; ratio = pcm3168a->sysclk / rate;

View File

@ -1163,6 +1163,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P") 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")
}
},
{ } { }
}; };

View File

@ -21,7 +21,6 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>

View File

@ -995,7 +995,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
rt5640->hp_mute = 1; rt5640->hp_mute = 1;
usleep_range(70000, 75000); msleep(70);
break; break;
default: default:
@ -1059,7 +1059,7 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
switch (event) { switch (event) {
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
if (!rt5640->hp_mute) if (!rt5640->hp_mute)
usleep_range(80000, 85000); msleep(80);
break; break;
@ -1227,6 +1227,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
RT5640_PWR_DAC_L1_BIT, 0, NULL, 0), RT5640_PWR_DAC_L1_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5640_PWR_DIG1, SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5640_PWR_DIG1,
RT5640_PWR_DAC_R1_BIT, 0, NULL, 0), 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 */ /* SPK/OUT Mixer */
SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT, 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)), 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)), rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
RT5640_PWR_MA_BIT, 0, NULL, 0), 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("MONOP"),
SND_SOC_DAPM_OUTPUT("MONON"), SND_SOC_DAPM_OUTPUT("MONON"),
@ -2313,6 +2313,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id rt5640_acpi_match[] = { static const struct acpi_device_id rt5640_acpi_match[] = {
{ "INT33CA", 0 }, { "INT33CA", 0 },
{ "10EC3276", 0 },
{ "10EC5640", 0 }, { "10EC5640", 0 },
{ "10EC5642", 0 }, { "10EC5642", 0 },
{ "INTCCFFD", 0 }, { "INTCCFFD", 0 },

View File

@ -3109,7 +3109,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
unsigned int val; unsigned int val;
if (jack_insert) { if (jack_insert) {
regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
/* for jack type detect */ /* for jack type detect */
snd_soc_dapm_force_enable_pin(dapm, "LDO2"); snd_soc_dapm_force_enable_pin(dapm, "LDO2");
@ -3545,8 +3545,10 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id rt5645_acpi_match[] = { static const struct acpi_device_id rt5645_acpi_match[] = {
{ "10EC5645", 0 }, { "10EC5645", 0 },
{ "10EC5648", 0 },
{ "10EC5650", 0 }, { "10EC5650", 0 },
{ "10EC5640", 0 }, { "10EC5640", 0 },
{ "10EC3270", 0 },
{}, {},
}; };
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
@ -3658,8 +3660,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
GPIOD_IN); GPIOD_IN);
if (IS_ERR(rt5645->gpiod_hp_det)) { if (IS_ERR(rt5645->gpiod_hp_det)) {
dev_err(&i2c->dev, "failed to initialize gpiod\n"); dev_info(&i2c->dev, "failed to initialize gpiod\n");
return PTR_ERR(rt5645->gpiod_hp_det); 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++) for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)

View File

@ -1150,28 +1150,28 @@ static const char * const rt5659_data_select[] = {
"L/R", "R/L", "L/L", "R/R" "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); 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); 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); 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); 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); 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); 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); 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); RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux = 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, 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_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); 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" "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_enum, RT5659_DAC_CTRL,
RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src); RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
static const struct snd_kcontrol_new rt5659_dac_l2_mux = static const struct snd_kcontrol_new rt5659_dac_l2_mux =
SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum); 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_enum, RT5659_DAC_CTRL,
RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src); RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
@ -1951,7 +1951,7 @@ static const char * const rt5659_sto1_adc1_src[] = {
"DAC MIX", "ADC" "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_enum, RT5659_STO1_ADC_MIXER,
RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src); RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
@ -1964,7 +1964,7 @@ static const char * const rt5659_sto1_adc_src[] = {
"ADC1", "ADC2" "ADC1", "ADC2"
}; };
static const SOC_ENUM_SINGLE_DECL( static SOC_ENUM_SINGLE_DECL(
rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER, rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src); RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
@ -1977,7 +1977,7 @@ static const char * const rt5659_sto1_adc2_src[] = {
"DAC MIX", "DMIC" "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_enum, RT5659_STO1_ADC_MIXER,
RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src); RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
@ -1990,7 +1990,7 @@ static const char * const rt5659_sto1_dmic_src[] = {
"DMIC1", "DMIC2" "DMIC1", "DMIC2"
}; };
static const SOC_ENUM_SINGLE_DECL( static SOC_ENUM_SINGLE_DECL(
rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER, rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src); RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
static const struct snd_kcontrol_new rt5659_mono_adc_l_mux = static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum); 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_adcr_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src); 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" "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_enum, RT5659_MONO_ADC_MIXER,
RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src); 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" "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_dac_r1_enum, RT5659_AD_DA_MIXER,
RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src); RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
static const struct snd_kcontrol_new rt5659_dac_r1_mux = static const struct snd_kcontrol_new rt5659_dac_r1_mux =
SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum); 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_dac_l1_enum, RT5659_AD_DA_MIXER,
RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src); 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" "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_dig_dac_mixl_enum, RT5659_DIG_MIXER,
RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src); RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux = static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum); 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_dig_dac_mixr_enum, RT5659_DIG_MIXER,
RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src); 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" "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_alg_dac_l1_enum, RT5659_A_DAC_MUX,
RT5659_A_DACL1_SFT, rt5659_alg_dac1_src); RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux = static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum); 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_alg_dac_r1_enum, RT5659_A_DAC_MUX,
RT5659_A_DACR1_SFT, rt5659_alg_dac1_src); 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" "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_alg_dac_l2_enum, RT5659_A_DAC_MUX,
RT5659_A_DACL2_SFT, rt5659_alg_dac2_src); RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux = static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum); 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_alg_dac_r2_enum, RT5659_A_DAC_MUX,
RT5659_A_DACR2_SFT, rt5659_alg_dac2_src); 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" "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_enum, RT5659_DIG_INF23_DATA,
RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src); 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" "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_enum, RT5659_DIG_INF23_DATA,
RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src); 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" "Mono DAC", "Stereo DAC"
}; };
static const SOC_ENUM_SINGLE_DECL( static SOC_ENUM_SINGLE_DECL(
rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL, rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
RT5659_PDM1_L_SFT, rt5659_pdm_src); RT5659_PDM1_L_SFT, rt5659_pdm_src);
static const struct snd_kcontrol_new rt5659_pdm_l_mux = static const struct snd_kcontrol_new rt5659_pdm_l_mux =
SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum); 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_pdm_r_enum, RT5659_PDM_OUT_CTRL,
RT5659_PDM1_R_SFT, rt5659_pdm_src); 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" "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_enum, RT5659_SPDIF_CTRL,
RT5659_SPDIF_SEL_SFT, rt5659_spdif_src); 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" "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_rx_adc_data_enum, RT5659_TDM_CTRL_2,
RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src); 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); GPIOD_OUT_HIGH);
/* Sleep for 300 ms miniumum */ /* Sleep for 300 ms miniumum */
usleep_range(300000, 350000); msleep(300);
rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap); rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
if (IS_ERR(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); MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
#endif #endif
struct i2c_driver rt5659_i2c_driver = { static struct i2c_driver rt5659_i2c_driver = {
.driver = { .driver = {
.name = "rt5659", .name = "rt5659",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rt5659_of_match), .of_match_table = of_match_ptr(rt5659_of_match),
.acpi_match_table = ACPI_PTR(rt5659_acpi_match), .acpi_match_table = ACPI_PTR(rt5659_acpi_match),
}, },

View File

@ -526,10 +526,10 @@ static const char * const rt5660_data_select[] = {
"L/R", "R/L", "L/L", "R/R" "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); 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); RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select);
static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux = 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); struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
if (rt5660->pdata.poweroff_codec_in_suspend) if (rt5660->pdata.poweroff_codec_in_suspend)
usleep_range(350000, 400000); msleep(350);
regcache_cache_only(rt5660->regmap, false); regcache_cache_only(rt5660->regmap, false);
regcache_sync(rt5660->regmap); regcache_sync(rt5660->regmap);

View File

@ -2814,6 +2814,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
static const struct acpi_device_id rt5670_acpi_match[] = { static const struct acpi_device_id rt5670_acpi_match[] = {
{ "10EC5670", 0}, { "10EC5670", 0},
{ "10EC5672", 0}, { "10EC5672", 0},
{ "10EC5640", 0}, /* quirk */
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);

View File

@ -21,7 +21,6 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>

View File

@ -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_PROGC_REG, pll_c);
snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d); 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 { } else {
/* /*
* Do soft reset to this codec instance in order to clear * Do soft reset to this codec instance in order to clear

View File

@ -21,7 +21,6 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/mutex.h> #include <linux/mutex.h>

View File

@ -855,6 +855,8 @@ ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_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("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_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) if (ret)
goto err_adsp2_codec_probe; 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_gpio(codec);
arizona_init_notifiers(codec); arizona_init_notifiers(codec);

View File

@ -778,6 +778,11 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), 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("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_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; 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_gpio(codec);
arizona_init_mono(codec); arizona_init_mono(codec);
arizona_init_notifiers(codec); arizona_init_notifiers(codec);

View File

@ -31,8 +31,8 @@
#define WM8731_CACHEREGNUM 10 #define WM8731_CACHEREGNUM 10
#define WM8731_SYSCLK_MCLK 0
#define WM8731_SYSCLK_XTAL 1 #define WM8731_SYSCLK_XTAL 1
#define WM8731_SYSCLK_MCLK 2
#define WM8731_DAI 0 #define WM8731_DAI 0

View File

@ -37,8 +37,6 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
"DVDD", "DVDD",
}; };
#define WM8741_NUM_RATES 6
/* codec private data */ /* codec private data */
struct wm8741_priv { struct wm8741_priv {
struct wm8741_platform_data pdata; struct wm8741_platform_data pdata;

View File

@ -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 DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
static const struct snd_kcontrol_new wm8753_snd_controls[] = { 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("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, 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; 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; ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae;
/* set master/slave audio interface */ /* set master/slave audio interface */

View File

@ -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_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); 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); arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS"); snd_soc_component_disable_pin(component, "HAPTICS");

View File

@ -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 wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(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 snd_soc_component *component = snd_soc_dapm_to_component(dapm);
int ret;
priv->core.arizona->dapm = dapm; 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_gpio(codec);
arizona_init_notifiers(codec); arizona_init_notifiers(codec);

View File

@ -2473,7 +2473,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
ret = wm_adsp2_ena(dsp); ret = wm_adsp2_ena(dsp);
if (ret != 0) if (ret != 0)
goto err_mutex; goto err_mem;
ret = wm_adsp_load(dsp); ret = wm_adsp_load(dsp);
if (ret != 0) if (ret != 0)
@ -2492,14 +2492,14 @@ static void wm_adsp2_boot_work(struct work_struct *work)
if (ret != 0) if (ret != 0)
goto err_ena; goto err_ena;
dsp->booted = true;
/* Turn DSP back off until we are ready to run */ /* Turn DSP back off until we are ready to run */
ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA, 0); ADSP2_SYS_ENA, 0);
if (ret != 0) if (ret != 0)
goto err_ena; goto err_ena;
dsp->booted = true;
mutex_unlock(&dsp->pwr_lock); mutex_unlock(&dsp->pwr_lock);
return; return;
@ -2507,6 +2507,9 @@ static void wm_adsp2_boot_work(struct work_struct *work)
err_ena: err_ena:
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 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: err_mutex:
mutex_unlock(&dsp->pwr_lock); 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); 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, int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event, struct snd_kcontrol *kcontrol, int event,
unsigned int freq) 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); queue_work(system_unbound_wq, &dsp->boot_work);
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
mutex_lock(&dsp->pwr_lock);
wm_adsp_debugfs_clear(dsp); wm_adsp_debugfs_clear(dsp);
dsp->fw_id = 0; 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); wm_adsp_free_alg_regions(dsp);
mutex_unlock(&dsp->pwr_lock);
adsp_dbg(dsp, "Shutdown complete\n"); adsp_dbg(dsp, "Shutdown complete\n");
break; break;
default: default:
@ -2575,8 +2619,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
flush_work(&dsp->boot_work); flush_work(&dsp->boot_work);
if (!dsp->booted) mutex_lock(&dsp->pwr_lock);
return -EIO;
if (!dsp->booted) {
ret = -EIO;
goto err;
}
ret = wm_adsp2_ena(dsp); ret = wm_adsp2_ena(dsp);
if (ret != 0) if (ret != 0)
@ -2594,18 +2642,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
if (ret != 0) if (ret != 0)
goto err; goto err;
dsp->running = true;
mutex_lock(&dsp->pwr_lock);
if (wm_adsp_fw[dsp->fw].num_caps != 0) { if (wm_adsp_fw[dsp->fw].num_caps != 0) {
ret = wm_adsp_buffer_init(dsp); ret = wm_adsp_buffer_init(dsp);
if (ret < 0) { if (ret < 0)
mutex_unlock(&dsp->pwr_lock);
goto err; goto err;
}
} }
dsp->running = true;
mutex_unlock(&dsp->pwr_lock); mutex_unlock(&dsp->pwr_lock);
break; break;
@ -2648,16 +2692,23 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
err: err:
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
mutex_unlock(&dsp->pwr_lock);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(wm_adsp2_event); EXPORT_SYMBOL_GPL(wm_adsp2_event);
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) 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); wm_adsp2_init_debugfs(dsp, codec);
dsp->codec = codec;
return snd_soc_add_codec_controls(codec, return snd_soc_add_codec_controls(codec,
&wm_adsp_fw_controls[dsp->num - 1], &wm_adsp_fw_controls[dsp->num - 1],
1); 1);

View File

@ -62,6 +62,7 @@ struct wm_adsp {
int fw; int fw;
int fw_ver; int fw_ver;
bool preloaded;
bool booted; bool booted;
bool running; bool running;
@ -86,7 +87,12 @@ struct wm_adsp {
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ 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) 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) \ #define WM_ADSP2(wname, num, event_fn) \
SND_SOC_DAPM_SPK(wname " Preload", NULL), \
{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ { .id = snd_soc_dapm_supply, .name = wname " Preloader", \
.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ .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, int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event); 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_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
int wm_adsp_compr_free(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, int wm_adsp_compr_set_params(struct snd_compr_stream *stream,

View File

@ -358,13 +358,20 @@ static struct snd_soc_card evm_soc_card = {
static int davinci_evm_probe(struct platform_device *pdev) static int davinci_evm_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match = 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 *dai = (struct snd_soc_dai_link *) match->data;
struct snd_soc_card_drvdata_davinci *drvdata = NULL; struct snd_soc_card_drvdata_davinci *drvdata = NULL;
struct clk *mclk; struct clk *mclk;
int ret = 0; 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; evm_soc_card.dai_link = dai;
dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0); dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);

View File

@ -121,9 +121,14 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
irq_valid = true; 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; irq_valid = true;
}
/* Error Handling: TX */ /* Error Handling: TX */
if (isr[i] & ISR_TXFO) { if (isr[i] & ISR_TXFO) {

View File

@ -41,10 +41,33 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
return tx_ptr; \ 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(16);
dw_pcm_tx_fn(32); dw_pcm_tx_fn(32);
dw_pcm_rx_fn(16);
dw_pcm_rx_fn(32);
#undef dw_pcm_tx_fn #undef dw_pcm_tx_fn
#undef dw_pcm_rx_fn
static const struct snd_pcm_hardware dw_pcm_hardware = { static const struct snd_pcm_hardware dw_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | .info = SNDRV_PCM_INFO_INTERLEAVED |
@ -57,6 +80,7 @@ static const struct snd_pcm_hardware dw_pcm_hardware = {
.rate_min = 32000, .rate_min = 32000,
.rate_max = 48000, .rate_max = 48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | .formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE, SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
@ -68,27 +92,51 @@ static const struct snd_pcm_hardware dw_pcm_hardware = {
.fifo_size = 16, .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; struct snd_pcm_substream *substream;
bool tx_active, period_elapsed; bool active, period_elapsed;
rcu_read_lock(); rcu_read_lock();
tx_substream = rcu_dereference(dev->tx_substream); if (push)
tx_active = tx_substream && snd_pcm_running(tx_substream); substream = rcu_dereference(dev->tx_substream);
if (tx_active) { else
unsigned int tx_ptr = READ_ONCE(dev->tx_ptr); substream = rcu_dereference(dev->rx_substream);
unsigned int new_tx_ptr = dev->tx_fn(dev, tx_substream->runtime, active = substream && snd_pcm_running(substream);
tx_ptr, &period_elapsed); if (active) {
cmpxchg(&dev->tx_ptr, tx_ptr, new_tx_ptr); 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) if (period_elapsed)
snd_pcm_period_elapsed(tx_substream); snd_pcm_period_elapsed(substream);
} }
rcu_read_unlock(); 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); 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) static int dw_pcm_open(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; 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)) { switch (params_format(hw_params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
dev->tx_fn = dw_pcm_tx_16; dev->tx_fn = dw_pcm_tx_16;
dev->rx_fn = dw_pcm_rx_16;
break; break;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_LE:
dev->tx_fn = dw_pcm_tx_32; dev->tx_fn = dw_pcm_tx_32;
dev->rx_fn = dw_pcm_rx_32;
break; break;
default: default:
dev_err(dev->dev, "invalid format\n"); dev_err(dev->dev, "invalid format\n");
return -EINVAL; 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, ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params)); params_buffer_bytes(hw_params));
if (ret < 0) 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_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
WRITE_ONCE(dev->tx_ptr, 0); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rcu_assign_pointer(dev->tx_substream, substream); 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; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 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; break;
default: default:
ret = -EINVAL; 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 snd_pcm_runtime *runtime = substream->runtime;
struct dw_i2s_dev *dev = runtime->private_data; 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; return pos < runtime->buffer_size ? pos : 0;
} }

View File

@ -105,20 +105,27 @@ struct dw_i2s_dev {
struct i2s_clk_config_data config; struct i2s_clk_config_data config;
int (*i2s_clk_cfg)(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; bool use_pio;
struct snd_pcm_substream __rcu *tx_substream; struct snd_pcm_substream __rcu *tx_substream;
struct snd_pcm_substream __rcu *rx_substream;
unsigned int (*tx_fn)(struct dw_i2s_dev *dev, unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
struct snd_pcm_runtime *runtime, unsigned int tx_ptr, struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
bool *period_elapsed); 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 tx_ptr;
unsigned int rx_ptr;
}; };
#if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM) #if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM)
void dw_pcm_push_tx(struct dw_i2s_dev *dev); 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); int dw_pcm_register(struct platform_device *pdev);
#else #else
void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } 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) int dw_pcm_register(struct platform_device *pdev)
{ {
return -EINVAL; return -EINVAL;

View File

@ -26,7 +26,6 @@
#include <sound/soc.h> #include <sound/soc.h>
#include "mpc5200_dma.h" #include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
#define DRV_NAME "efika-audio-fabric" #define DRV_NAME "efika-audio-fabric"

View File

@ -668,7 +668,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
.playback = { .playback = {
.stream_name = "CPU-Playback", .stream_name = "CPU-Playback",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 32,
.rate_min = 8000, .rate_min = 8000,
.rate_max = 192000, .rate_max = 192000,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,
@ -677,7 +677,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
.capture = { .capture = {
.stream_name = "CPU-Capture", .stream_name = "CPU-Capture",
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 32,
.rate_min = 8000, .rate_min = 8000,
.rate_max = 192000, .rate_max = 192000,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,

View File

@ -25,7 +25,6 @@
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
#include "mpc5200_dma.h" #include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
#define DRV_NAME "mpc5200-psc-ac97" #define DRV_NAME "mpc5200-psc-ac97"

View File

@ -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__ */

View File

@ -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); 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 device_node *dai_of_node,
struct asoc_simple_dai *simple_dai) 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 "system-clock-frequency = <xxx>"
* or device's module clock. * or device's module clock.
*/ */
clk = of_clk_get(node, 0); clk = devm_get_clk_from_child(dev, node, NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk); simple_dai->sysclk = clk_get_rate(clk);
simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val; simple_dai->sysclk = val;
} else { } else {
clk = of_clk_get(dai_of_node, 0); clk = devm_get_clk_from_child(dev, dai_of_node, NULL);
if (!IS_ERR(clk)) if (!IS_ERR(clk))
simple_dai->sysclk = clk_get_rate(clk); simple_dai->sysclk = clk_get_rate(clk);
} }

View File

@ -278,11 +278,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = 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) if (ret < 0)
goto dai_link_of_err; 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) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;

View File

@ -128,7 +128,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret) if (ret)
return 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) if (ret < 0)
return ret; return ret;
@ -153,7 +153,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0) if (ret < 0)
return ret; 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) if (ret < 0)
return ret; return ret;

View File

@ -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); struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
unsigned int rate, channels; unsigned int rate, channels;
u32 reg, control_set = 0; u32 reg, control_set = 0;
snd_pcm_format_t format;
rate = params_rate(params); rate = params_rate(params);
format = params_format(params);
channels = params_channels(params); channels = params_channels(params);
switch (params_format(params)) { switch (params_format(params)) {

View File

@ -2,7 +2,7 @@ config SND_MFLD_MACHINE
tristate "SOC Machine Audio driver for Intel Medfield MID platform" tristate "SOC Machine Audio driver for Intel Medfield MID platform"
depends on INTEL_SCU_IPC depends on INTEL_SCU_IPC
select SND_SOC_SN95031 select SND_SOC_SN95031
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_PCI select SND_SST_IPC_PCI
help help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform 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. Say Y if you have such a device.
If unsure select "N". If unsure select "N".
config SND_SST_MFLD_PLATFORM config SND_SST_ATOM_HIFI2_PLATFORM
tristate tristate
select SND_SOC_COMPRESS select SND_SOC_COMPRESS
@ -31,13 +31,10 @@ config SND_SOC_INTEL_SST
tristate tristate
select SND_SOC_INTEL_SST_ACPI if ACPI select SND_SOC_INTEL_SST_ACPI if ACPI
select SND_SOC_INTEL_SST_MATCH 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 config SND_SOC_INTEL_SST_FIRMWARE
tristate tristate
select DW_DMAC_CORE
config SND_SOC_INTEL_SST_ACPI config SND_SOC_INTEL_SST_ACPI
tristate tristate
@ -47,16 +44,18 @@ config SND_SOC_INTEL_SST_MATCH
config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL
tristate tristate
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_BAYTRAIL
tristate tristate
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE depends on DMADEVICES
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
@ -68,7 +67,6 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
depends on X86 && ACPI && I2C depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_DA7219 select SND_SOC_DA7219
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
@ -84,7 +82,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BXT_RT298_MACH
tristate "ASoC Audio driver for Broxton with RT298 I2S mode" tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
depends on X86 && ACPI && I2C depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT298 select SND_SOC_RT298
select SND_SOC_DMIC select SND_SOC_DMIC
@ -99,9 +96,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) depends on DMADEVICES
select SND_SOC_INTEL_SST depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_BAYTRAIL select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
@ -112,9 +108,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) depends on DMADEVICES
select SND_SOC_INTEL_SST depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_BAYTRAIL select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090 select SND_SOC_MAX98090
help help
@ -123,9 +118,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BDW_RT5677_MACH config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC depends on X86_INTEL_LPSS && GPIOLIB && I2C
depends on DW_DMAC_CORE=y depends on DMADEVICES
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5677 select SND_SOC_RT5677
help help
@ -134,10 +128,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
config SND_SOC_INTEL_BROADWELL_MACH config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
I2C_DESIGNWARE_PLATFORM depends on DMADEVICES
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286 select SND_SOC_RT286
help 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" tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
depends on X86 && I2C && ACPI depends on X86 && I2C && ACPI
select SND_SOC_RT5640 select SND_SOC_RT5640
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help 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" tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
depends on X86 && I2C && ACPI depends on X86 && I2C && ACPI
select SND_SOC_RT5651 select SND_SOC_RT5651
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help help
@ -176,7 +168,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5670 select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help 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" tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5645 select SND_SOC_RT5645
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help help
@ -202,7 +194,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
depends on X86_INTEL_LPSS && I2C && ACPI depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_MAX98090 select SND_SOC_MAX98090
select SND_SOC_TS3A227E select SND_SOC_TS3A227E
select SND_SST_MFLD_PLATFORM select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help help
@ -220,7 +212,6 @@ config SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode" tristate "ASoC Audio driver for SKL with RT286 I2S mode"
depends on X86 && ACPI && I2C depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286 select SND_SOC_RT286
select SND_SOC_DMIC select SND_SOC_DMIC
@ -234,7 +225,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_SSM4567 select SND_SOC_SSM4567
@ -249,7 +239,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_MAX98357A select SND_SOC_MAX98357A

View File

@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
# Platform Support # Platform Support
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ 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/ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
# Machine support # Machine support

View File

@ -1,7 +1,8 @@
snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \
sst-mfld-platform-compress.o sst-atom-controls.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 # DSP driver
obj-$(CONFIG_SND_SST_IPC) += sst/ obj-$(CONFIG_SND_SST_IPC) += sst/

View File

@ -801,13 +801,11 @@ static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai,
switch (format) { switch (format) {
case SND_SOC_DAIFMT_NB_NF: 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: case SND_SOC_DAIFMT_IB_NF:
return SSP_FS_ACTIVE_HIGH; return SSP_FS_ACTIVE_HIGH;
case SND_SOC_DAIFMT_NB_IF:
case SND_SOC_DAIFMT_IB_IF:
return SSP_FS_ACTIVE_LOW;
default: default:
dev_err(dai->dev, "Invalid frame sync polarity %d\n", format); 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("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_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_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("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_MONO, 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), 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 */ /* Media Mixers */

View File

@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct sst_runtime_stream *stream; struct sst_runtime_stream *stream;
int ret_val = 0, str_id; int str_id;
stream = substream->runtime->private_data; stream = substream->runtime->private_data;
power_down_sst(stream); power_down_sst(stream);
str_id = stream->stream_info.str_id; str_id = stream->stream_info.str_id;
if (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); module_put(sst->dev->driver->owner);
kfree(stream); kfree(stream);
} }
@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sst-atom-hifi2-platform");
MODULE_ALIAS("platform:sst-mfld-platform"); MODULE_ALIAS("platform:sst-mfld-platform");

View File

@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev)
static unsigned long cht_machine_id; static unsigned long cht_machine_id;
#define CHT_SURFACE_MACH 1 #define CHT_SURFACE_MACH 1
#define BYT_THINKPAD_10 2
static int cht_surface_quirk_cb(const struct dmi_system_id *id) 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; 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[] = { 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, "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }; &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) static struct sst_acpi_mach *cht_quirk(void *arg)
{ {
struct sst_acpi_mach *mach = arg; struct sst_acpi_mach *mach = arg;
@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg)
return mach; 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[] = { 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 }, &byt_rvp_platform_data },
{"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
&byt_rvp_platform_data }, &byt_rvp_platform_data },
@ -445,6 +480,12 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
&byt_rvp_platform_data }, &byt_rvp_platform_data },
{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
&byt_rvp_platform_data }, &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 }, &chv_platform_data },
{"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }, &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, {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }, &chv_platform_data },
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
&chv_platform_data }, &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 },
{}, {},
}; };

View File

@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
u32 data_size, i; u32 data_size, i;
void *data_offset; void *data_offset;
struct stream_info *stream; struct stream_info *stream;
union ipc_header_high msg_high;
u32 msg_low, pipe_id; u32 msg_low, pipe_id;
msg_high = msg->mrfld_header.p.header_high;
msg_low = msg->mrfld_header.p.header_low_payload; msg_low = msg->mrfld_header.p.header_low_payload;
msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));

View File

@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
{ {
int retval = 0; int retval = 0;
struct stream_info *str_info; 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); 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); str_info = get_stream_info(sst_drv_ctx, str_id);
if (!str_info) if (!str_info)
return -EINVAL; return -EINVAL;
ops = sst_drv_ctx->ops;
mutex_lock(&str_info->lock); mutex_lock(&str_info->lock);
if (str_info->status != STREAM_UN_INIT) { if (str_info->status != STREAM_UN_INIT) {

View File

@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev)
{ {
broadwell_rt286.dev = &pdev->dev; broadwell_rt286.dev = &pdev->dev;
snd_soc_set_dmi_name(&broadwell_rt286, NULL);
return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
} }

View File

@ -33,6 +33,17 @@
#define QUAD_CHANNEL 4 #define QUAD_CHANNEL 4
static struct snd_soc_jack broxton_headset; 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 { enum {
BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_PB = 0,
@ -84,9 +95,9 @@ static const struct snd_soc_dapm_route broxton_map[] = {
{"codec0_in", NULL, "ssp1 Rx"}, {"codec0_in", NULL, "ssp1 Rx"},
{"ssp1 Rx", NULL, "Capture"}, {"ssp1 Rx", NULL, "Capture"},
{"HDMI1", NULL, "hif5 Output"}, {"HDMI1", NULL, "hif5-0 Output"},
{"HDMI2", NULL, "hif6 Output"}, {"HDMI2", NULL, "hif6-0 Output"},
{"HDMI3", NULL, "hif7 Output"}, {"HDMI2", NULL, "hif7-0 Output"},
{"hifi3", NULL, "iDisp3 Tx"}, {"hifi3", NULL, "iDisp3 Tx"},
{"iDisp3 Tx", NULL, "iDisp3_out"}, {"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) 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 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) 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", .platform_name = "0000:00:0e.0",
.init = NULL, .init = NULL,
.dpcm_capture = 1, .dpcm_capture = 1,
.ignore_suspend = 1,
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
.ops = &broxton_refcap_ops, .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 */ /* broxton audio machine driver for SPT + da7219 */
static struct snd_soc_card broxton_audio_card = { static struct snd_soc_card broxton_audio_card = {
.name = "bxtda7219max", .name = "bxtda7219max",
@ -510,11 +565,22 @@ static struct snd_soc_card broxton_audio_card = {
.dapm_routes = broxton_map, .dapm_routes = broxton_map,
.num_dapm_routes = ARRAY_SIZE(broxton_map), .num_dapm_routes = ARRAY_SIZE(broxton_map),
.fully_routed = true, .fully_routed = true,
.late_probe = bxt_card_late_probe,
}; };
static int broxton_audio_probe(struct platform_device *pdev) 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; 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); return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
} }

View File

@ -26,8 +26,19 @@
#include "../../codecs/hdac_hdmi.h" #include "../../codecs/hdac_hdmi.h"
#include "../../codecs/rt298.h" #include "../../codecs/rt298.h"
static struct snd_soc_jack broxton_headset;
/* Headset jack detection DAPM pins */ /* 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 { enum {
BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_PB = 0,
@ -82,9 +93,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
{"DMIC1 Pin", NULL, "DMIC2"}, {"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"}, {"DMic", NULL, "SoC DMIC"},
{"HDMI1", NULL, "hif5 Output"}, {"HDMI1", NULL, "hif5-0 Output"},
{"HDMI2", NULL, "hif6 Output"}, {"HDMI2", NULL, "hif6-0 Output"},
{"HDMI3", NULL, "hif7 Output"}, {"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */ /* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp5 Tx"}, { "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) 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 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, 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 */ /* broxton audio machine driver for SPT + RT298S */
static struct snd_soc_card broxton_rt298 = { static struct snd_soc_card broxton_rt298 = {
.name = "broxton-rt298", .name = "broxton-rt298",
@ -445,11 +502,22 @@ static struct snd_soc_card broxton_rt298 = {
.dapm_routes = broxton_rt298_map, .dapm_routes = broxton_rt298_map,
.num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
.fully_routed = true, .fully_routed = true,
.late_probe = bxt_card_late_probe,
}; };
static int broxton_audio_probe(struct platform_device *pdev) 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; broxton_rt298.dev = &pdev->dev;
snd_soc_card_set_drvdata(&broxton_rt298, ctx);
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
} }

View File

@ -386,6 +386,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_MCLK_EN | BYT_RT5640_MCLK_EN |
BYT_RT5640_SSP0_AIF1), 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, ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBS_CFS
); );
if (ret < 0) { 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, ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBS_CFS
); );
if (ret < 0) { 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 = { static struct platform_driver snd_byt_rt5640_mc_driver = {
.driver = { .driver = {
.name = "bytcr_rt5640", .name = "bytcr_rt5640",
.pm = &snd_soc_pm_ops,
}, },
.probe = snd_byt_rt5640_mc_probe, .probe = snd_byt_rt5640_mc_probe,
}; };

View File

@ -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, ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS 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 = { static struct platform_driver snd_byt_rt5651_mc_driver = {
.driver = { .driver = {
.name = "bytcr_rt5651", .name = "bytcr_rt5651",
.pm = &snd_soc_pm_ops,
}, },
.probe = snd_byt_rt5651_mc_probe, .probe = snd_byt_rt5651_mc_probe,
}; };

View File

@ -23,7 +23,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dmi.h>
#include <linux/slab.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.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
@ -33,7 +37,8 @@
#include "../common/sst-acpi.h" #include "../common/sst-acpi.h"
#define CHT_PLAT_CLK_3_HZ 19200000 #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 { struct cht_acpi_card {
char *codec_id; char *codec_id;
@ -45,15 +50,36 @@ struct cht_mc_private {
struct snd_soc_jack jack; struct snd_soc_jack jack;
struct cht_acpi_card *acpi_card; struct cht_acpi_card *acpi_card;
char codec_name[16]; 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) static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd; struct snd_soc_pcm_runtime *rtd;
list_for_each_entry(rtd, &card->rtd_list, list) { list_for_each_entry(rtd, &card->rtd_list, list) {
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1,
strlen(CHT_CODEC_DAI))) 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 rtd->codec_dai;
} }
return NULL; 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_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card; struct snd_soc_card *card = dapm->card;
struct snd_soc_dai *codec_dai; struct snd_soc_dai *codec_dai;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret; int ret;
codec_dai = cht_get_codec_dai(card); codec_dai = cht_get_codec_dai(card);
@ -73,19 +100,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return -EIO; return -EIO;
} }
if (!SND_SOC_DAPM_EVENT_OFF(event)) if (SND_SOC_DAPM_EVENT_ON(event)) {
return 0; 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 if (ctx->mclk)
* be off when idle and MCLK will also be off by ACPI when codec is clk_disable_unprepare(ctx->mclk);
* 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;
} }
return 0; 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_MIC("Int Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, 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[] = { 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"}, {"Headphone", NULL, "HPOR"},
{"Ext Spk", NULL, "SPOL"}, {"Ext Spk", NULL, "SPOL"},
{"Ext Spk", NULL, "SPOR"}, {"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"}, {"Headphone", NULL, "Platform Clock"},
{"Headset Mic", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"},
{"Int 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"}, {"Headphone", NULL, "HPOR"},
{"Ext Spk", NULL, "SPOL"}, {"Ext Spk", NULL, "SPOL"},
{"Ext Spk", NULL, "SPOR"}, {"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"}, {"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out0"},
{"ssp2 Tx", NULL, "codec_out1"}, {"ssp2 Tx", NULL, "codec_out1"},
{"codec_in0", NULL, "ssp2 Rx" }, {"codec_in0", NULL, "ssp2 Rx" },
{"codec_in1", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" },
{"ssp2 Rx", NULL, "AIF1 Capture"}, {"ssp2 Rx", NULL, "AIF1 Capture"},
{"Headphone", NULL, "Platform Clock"}, };
{"Headset Mic", NULL, "Platform Clock"},
{"Int Mic", NULL, "Platform Clock"}, static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = {
{"Ext Spk", NULL, "Platform Clock"}, {"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[] = { 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; 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) static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{ {
int ret; int ret;
int jack_type; int jack_type;
struct snd_soc_codec *codec = runtime->codec; 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); struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
/* Select clk_i2s1_asrc as ASRC clock source */ if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
rt5645_sel_asrc_clk_src(codec, (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
RT5645_DA_STEREO_FILTER | /* Select clk_i2s2_asrc as ASRC clock source */
RT5645_DA_MONO_L_FILTER | rt5645_sel_asrc_clk_src(codec,
RT5645_DA_MONO_R_FILTER | RT5645_DA_STEREO_FILTER |
RT5645_AD_STEREO_FILTER, RT5645_DA_MONO_L_FILTER |
RT5645_CLK_SEL_I2S1_ASRC); RT5645_DA_MONO_R_FILTER |
RT5645_AD_STEREO_FILTER,
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ RT5645_CLK_SEL_I2S2_ASRC);
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); } else {
if (ret < 0) { /* Select clk_i2s1_asrc as ASRC clock source */
dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); rt5645_sel_asrc_clk_src(codec,
return ret; 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) if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650)
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | 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); 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; return ret;
} }
static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
int ret;
struct snd_interval *rate = hw_param_interval(params, struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE); SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params, 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; rate->min = rate->max = 48000;
channels->min = channels->max = 2; channels->min = channels->max = 2;
/* set SSP2 to 24-bit */ if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); (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; return 0;
} }
@ -303,8 +478,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.no_pcm = 1, .no_pcm = 1,
.codec_dai_name = "rt5645-aif1", .codec_dai_name = "rt5645-aif1",
.codec_name = "i2c-10EC5645:00", .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, .init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup, .be_hw_params_fixup = cht_codec_fixup,
.nonatomic = true, .nonatomic = true,
@ -344,10 +517,31 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
static struct cht_acpi_card snd_soc_cards[] = { static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
{"10EC5645", 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}, {"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) 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; struct sst_acpi_mach *mach;
const char *i2c_name = NULL; const char *i2c_name = NULL;
int dai_index = 0; int dai_index = 0;
bool found = false;
bool is_bytcr = false;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv) if (!drv)
return -ENOMEM; return -ENOMEM;
mach = (&pdev->dev)->platform_data;
for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { 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, dev_dbg(&pdev->dev,
"found codec %s\n", snd_soc_cards[i].codec_id); "found codec %s\n", snd_soc_cards[i].codec_id);
card = snd_soc_cards[i].soc_card; card = snd_soc_cards[i].soc_card;
drv->acpi_card = &snd_soc_cards[i]; drv->acpi_card = &snd_soc_cards[i];
found = true;
break; break;
} }
} }
if (!found) {
dev_err(&pdev->dev, "No matching HID found in supported list\n");
return -ENODEV;
}
card->dev = &pdev->dev; card->dev = &pdev->dev;
mach = card->dev->platform_data;
sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
/* set correct codec name */ /* set correct codec name */
@ -386,9 +591,105 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* fixup codec name based on HID */ /* fixup codec name based on HID */
i2c_name = sst_acpi_find_name_from_hid(mach->id); i2c_name = sst_acpi_find_name_from_hid(mach->id);
if (i2c_name != NULL) { 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); "%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); snd_soc_card_set_drvdata(card, drv);

View File

@ -32,6 +32,7 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints; static const struct snd_pcm_hw_constraint_list *dmic_constraints;
static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct skl_hdmi_pcm {
struct list_head head; 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_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_SPK("Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("DP1", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("DP2", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU | platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMD),
@ -130,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{ "MIC", NULL, "Headset Mic" }, { "MIC", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" }, { "DMic", NULL, "SoC DMIC" },
{"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"},
/* CODEC BE connections */ /* CODEC BE connections */
{ "HiFi Playback", NULL, "ssp0 Tx" }, { "HiFi Playback", NULL, "ssp0 Tx" },
{ "ssp0 Tx", NULL, "codec0_out" }, { "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) static int skylake_card_late_probe(struct snd_soc_card *card)
{ {
struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm; 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) { 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) if (err < 0)
return err; 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 */ /* skylake audio machine driver for SPT + NAU88L25 */

View File

@ -36,6 +36,7 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints; static const struct snd_pcm_hw_constraint_list *dmic_constraints;
static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct skl_hdmi_pcm {
struct list_head head; 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("Left Speaker", NULL),
SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("DP1", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("DP2", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU | platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_POST_PMD),
@ -135,8 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{"MIC", NULL, "Headset Mic"}, {"MIC", NULL, "Headset Mic"},
{"DMic", NULL, "SoC DMIC"}, {"DMic", NULL, "SoC DMIC"},
{"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"},
/* CODEC BE connections */ /* CODEC BE connections */
{ "Left Playback", NULL, "ssp0 Tx"}, { "Left Playback", NULL, "ssp0 Tx"},
{ "Right 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) static int skylake_card_late_probe(struct snd_soc_card *card)
{ {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm; 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) { 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) if (err < 0)
return err; 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 */ /* skylake audio machine driver for SPT + NAU88L25 */

View File

@ -29,6 +29,7 @@
#include "../../codecs/hdac_hdmi.h" #include "../../codecs/hdac_hdmi.h"
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct skl_hdmi_pcm {
struct list_head head; struct list_head head;
@ -94,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{"DMIC1 Pin", NULL, "DMIC2"}, {"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"}, {"DMic", NULL, "SoC DMIC"},
{"HDMI1", NULL, "hif5 Output"},
{"HDMI2", NULL, "hif6 Output"},
{"HDMI3", NULL, "hif7 Output"},
/* CODEC BE connections */ /* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp0 Tx"}, { "AIF1 Playback", NULL, "ssp0 Tx"},
{ "ssp0 Tx", NULL, "codec0_out"}, { "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) static int skylake_card_late_probe(struct snd_soc_card *card)
{ {
struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
struct skl_hdmi_pcm *pcm; 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) { 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) if (err < 0)
return err; 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 */ /* skylake audio machine driver for SPT + RT286S */

View File

@ -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); EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, 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; 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 * split the loop into sleeps of varying resolution. more accurately,
* then go to longer sleep using usleep_range * 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 */ timeout = jiffies + msecs_to_jiffies(time);
for (time = 0; time < 5; time++) { while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) { && time_before(jiffies, timeout)) {
done = true; k++;
break; if (k > 10)
} s = 5000;
mdelay(1);
}
if (done == false) { usleep_range(s, 2*s);
/* 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);
}
} }
reg = sst_dsp_shim_read_unlocked(ctx, offset); 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); EXPORT_SYMBOL_GPL(sst_dsp_register_poll);

View File

@ -23,7 +23,6 @@
#include "../common/sst-dsp.h" #include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h" #include "../common/sst-dsp-priv.h"
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
#include "skl-tplg-interface.h"
#define BXT_BASEFW_TIMEOUT 3000 #define BXT_BASEFW_TIMEOUT 3000
#define BXT_INIT_TIMEOUT 500 #define BXT_INIT_TIMEOUT 500
@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
} }
static int 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 snd_dma_buffer dmab;
struct skl_sst *skl = ctx->thread_context; 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; int ret = 0, i, dma_id, stream_tag;
/* library indices start from 1 to N. 0 represents base FW */ /* library indices start from 1 to N. 0 represents base FW */
for (i = 1; i < minfo->lib_count; i++) { for (i = 1; i < lib_count; i++) {
ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); ret = request_firmware(&fw, linfo[i].name, ctx->dev);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Request lib %s failed:%d\n", dev_err(ctx->dev, "Request lib %s failed:%d\n",
minfo->lib[i].name, ret); linfo[i].name, ret);
return 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); ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i);
if (ret < 0) if (ret < 0)
dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", 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.trigger(ctx->dev, false, stream_tag);
ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
@ -119,8 +118,7 @@ load_library_failed:
static int sst_bxt_prepare_fw(struct sst_dsp *ctx, static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
const void *fwdata, u32 fwsize) const void *fwdata, u32 fwsize)
{ {
int stream_tag, ret, i; int stream_tag, ret;
u32 reg;
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
if (stream_tag <= 0) { if (stream_tag <= 0) {
@ -153,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
} }
/* Step 4: Wait for DONE Bit */ /* Step 4: Wait for DONE Bit */
for (i = BXT_INIT_TIMEOUT; i > 0; --i) { ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE,
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,
SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE,
SKL_ADSP_REG_HIPCIE_DONE); SKL_ADSP_REG_HIPCIE_DONE,
break; BXT_INIT_TIMEOUT, "HIPCIE Done");
} if (ret < 0) {
mdelay(1); dev_err(ctx->dev, "Timout for Purge Request%d\n", ret);
} goto base_fw_load_failed;
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);
} }
/* Step 5: power down core1 */ /* 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); skl_ipc_op_int_enable(ctx);
/* Step 7: Wait for ROM init */ /* Step 7: Wait for ROM init */
for (i = BXT_INIT_TIMEOUT; i > 0; --i) { ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
if (SKL_FW_INIT == SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load");
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & if (ret < 0) {
SKL_FW_STS_MASK)) { dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
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;
goto base_fw_load_failed; 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; int ret;
struct skl_ipc_dxstate_info dx; struct skl_ipc_dxstate_info dx;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
struct skl_dfw_manifest *minfo = &skl->manifest;
if (skl->fw_loaded == false) { if (skl->fw_loaded == false) {
skl->boot_complete = 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; return ret;
} }
if (minfo->lib_count > 1) { if (skl->lib_count > 1) {
ret = bxt_load_library(ctx, minfo); ret = bxt_load_library(ctx, skl->lib_info,
skl->lib_count);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "reload libs failed: %d\n", ret); dev_err(ctx->dev, "reload libs failed: %d\n", ret);
return 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); skl_dsp_init_core_state(sst);
if (ctx->manifest.lib_count > 1) { if (ctx->lib_count > 1) {
ret = sst->fw_ops.load_library(sst, &ctx->manifest); ret = sst->fw_ops.load_library(sst, ctx->lib_info,
ctx->lib_count);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Load Library failed : %x\n", ret); dev_err(dev, "Load Library failed : %x\n", ret);
return ret; return ret;

View File

@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = {
.init_fw = bxt_sst_init_fw, .init_fw = bxt_sst_init_fw,
.cleanup = bxt_sst_dsp_cleanup .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) const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)

View File

@ -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, 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", dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
epnt->virtual_bus_id, epnt->linktype, epnt->direction); epnt->virtual_bus_id, epnt->linktype,
epnt->direction, epnt->device_type);
if ((epnt->virtual_bus_id == instance_id) && if ((epnt->virtual_bus_id == instance_id) &&
(epnt->linktype == link_type) && (epnt->linktype == link_type) &&
(epnt->direction == dirn)) (epnt->direction == dirn) &&
(epnt->device_type == dev_type))
return true; return true;
else else
return false; return false;
@ -117,7 +119,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
struct nhlt_specific_cfg struct nhlt_specific_cfg
*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, *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_fmt *fmt;
struct nhlt_endpoint *epnt; struct nhlt_endpoint *epnt;
@ -135,7 +138,8 @@ struct nhlt_specific_cfg
dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
for (j = 0; j < nhlt->endpoint_count; j++) { 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 + fmt = (struct nhlt_fmt *)(epnt->config.caps +
epnt->config.size); epnt->config.size);
sp_config = skl_get_specific_cfg(dev, fmt, num_ch, 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; 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 cnt;
int i; 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, skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
nhlt->header.oem_revision, "-tplg.bin"); nhlt->header.oem_revision, "-tplg.bin");
skl_nhlt_trim_space(skl); skl_nhlt_trim_space(skl->tplg_name);
return 0; 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);
}

View File

@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
skl->supend_active--; 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, static int skl_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
@ -188,32 +262,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
return 0; 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, static int skl_be_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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, static int skl_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct skl *skl = get_skl_ctx(dai->dev); struct skl *skl = get_skl_ctx(dai->dev);
unsigned int format_val;
int err;
struct skl_module_cfg *mconfig; struct skl_module_cfg *mconfig;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 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 */ /* In case of XRUN recovery, reset the FW pipe to clean state */
if (mconfig && (substream->runtime->status->state == if (mconfig && (substream->runtime->status->state ==
SNDRV_PCM_STATE_XRUN)) SNDRV_PCM_STATE_XRUN))
skl_reset_pipe(skl->skl_sst, mconfig->pipe); skl_reset_pipe(skl->skl_sst, mconfig->pipe);
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); return 0;
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;
} }
static int skl_pcm_hw_params(struct snd_pcm_substream *substream, 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.s_freq = params_rate(params);
p_params.host_dma_id = dma_id; p_params.host_dma_id = dma_id;
p_params.stream = substream->stream; p_params.stream = substream->stream;
p_params.format = params_format(params);
m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
if (m_cfg) if (m_cfg)
@ -438,7 +469,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
if (!w->ignore_suspend) { if (!w->ignore_suspend) {
skl_pcm_prepare(substream, dai);
/* /*
* enable DMA Resume enable bit for the stream, set the * enable DMA Resume enable bit for the stream, set the
* dpib & lpib position to resume before starting 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, snd_hdac_ext_stream_drsm_enable(ebus, true,
hdac_stream(stream)->index); hdac_stream(stream)->index);
snd_hdac_ext_stream_set_dpibr(ebus, stream, snd_hdac_ext_stream_set_dpibr(ebus, stream,
stream->dpib); stream->lpib);
snd_hdac_ext_stream_set_lpib(stream, 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 * pipeline is started but there is a delay in starting the
* DMA channel on the host. * DMA channel on the host.
*/ */
snd_hdac_ext_stream_decouple(ebus, stream, true);
ret = skl_decoupled_trigger(substream, cmd); ret = skl_decoupled_trigger(substream, cmd);
if (ret < 0) if (ret < 0)
return ret; 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_bus *ebus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *link_dev; struct hdac_ext_stream *link_dev;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 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 snd_soc_dai *codec_dai = rtd->codec_dai;
struct skl_pipe_params p_params = {0}; struct skl_pipe_params p_params = {0};
struct hdac_ext_link *link;
int stream_tag;
link_dev = snd_hdac_ext_stream_assign(ebus, substream, link_dev = snd_hdac_ext_stream_assign(ebus, substream,
HDAC_EXT_STREAM_TYPE_LINK); 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); 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 */ /* set the stream tag in the codec dai dma params */
dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
if (dma_params)
dma_params->stream_tag = hdac_stream(link_dev)->stream_tag;
p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.s_fmt = snd_pcm_format_width(params_format(params));
p_params.ch = params_channels(params); p_params.ch = params_channels(params);
p_params.s_freq = params_rate(params); p_params.s_freq = params_rate(params);
p_params.stream = substream->stream; 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); 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, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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 *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig = NULL; 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 */ /* In case of XRUN recovery, reset the FW pipe to clean state */
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
if (mconfig && (substream->runtime->status->state == if (mconfig && !mconfig->pipe->passthru &&
SNDRV_PCM_STATE_XRUN)) (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN))
skl_reset_pipe(skl->skl_sst, mconfig->pipe); 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; 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); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
skl_link_pcm_prepare(substream, dai);
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_stream_decouple(ebus, stream, true);
snd_hdac_ext_link_stream_start(link_dev); snd_hdac_ext_link_stream_start(link_dev);
break; break;

View File

@ -19,7 +19,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <sound/memalloc.h> #include <sound/memalloc.h>
#include "skl-sst-cldma.h" #include "skl-sst-cldma.h"
#include "skl-tplg-interface.h"
#include "skl-topology.h" #include "skl-topology.h"
struct sst_dsp; struct sst_dsp;
@ -145,7 +144,7 @@ struct skl_dsp_fw_ops {
int (*load_fw)(struct sst_dsp *ctx); int (*load_fw)(struct sst_dsp *ctx);
/* FW module parser/loader */ /* FW module parser/loader */
int (*load_library)(struct sst_dsp *ctx, 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 (*parse_fw)(struct sst_dsp *ctx);
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
int (*set_state_D3)(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); void skl_freeup_uuid_list(struct skl_sst *ctx);
int skl_dsp_strip_extended_manifest(struct firmware *fw); int skl_dsp_strip_extended_manifest(struct firmware *fw);
#endif /*__SKL_SST_DSP_H__*/ #endif /*__SKL_SST_DSP_H__*/

View File

@ -97,8 +97,9 @@ struct skl_sst {
/* multi-core */ /* multi-core */
struct skl_dsp_cores cores; struct skl_dsp_cores cores;
/* tplg manifest */ /* library info */
struct skl_dfw_manifest manifest; struct skl_lib_info lib_info[SKL_MAX_LIB];
int lib_count;
/* Callback to update D0i3C register */ /* Callback to update D0i3C register */
void (*update_d0i3c)(struct device *dev, bool enable); void (*update_d0i3c)(struct device *dev, bool enable);

View File

@ -330,6 +330,31 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
multiplier; 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, static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx) 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; u32 ch, s_freq, s_fmt;
struct nhlt_specific_cfg *cfg; struct nhlt_specific_cfg *cfg;
struct skl *skl = get_skl_ctx(ctx->dev); 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 */ /* check if we already have blob */
if (m_cfg->formats_config.caps_size > 0) 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 */ /* update the blob based on virtual bus_id and default params */
cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, 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) { if (cfg) {
m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps_size = cfg->size;
m_cfg->formats_config.caps = (u32 *) &cfg->caps; 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; 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 * 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 * 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; 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 */ /* update blob if blob is null for be with default value */
skl_tplg_update_be_blob(w, ctx); 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_module_cfg *src_module = NULL, *dst_module;
struct skl_sst *ctx = skl->skl_sst; struct skl_sst *ctx = skl->skl_sst;
struct skl_pipe *s_pipe = mconfig->pipe; struct skl_pipe *s_pipe = mconfig->pipe;
int ret = 0;
if (s_pipe->state == SKL_PIPE_INVALID) if (s_pipe->state == SKL_PIPE_INVALID)
return -EINVAL; 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; 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); 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) { switch (mcfg->dev_type) {
case SKL_DEVICE_HDALINK: case SKL_DEVICE_HDALINK:
pipe->p_params->link_dma_id = params->link_dma_id; pipe->p_params->link_dma_id = params->link_dma_id;
pipe->p_params->link_index = params->link_index;
break; break;
case SKL_DEVICE_HDAHOST: 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->ch = params->ch;
pipe->p_params->s_freq = params->s_freq; pipe->p_params->s_freq = params->s_freq;
pipe->p_params->stream = params->stream; pipe->p_params->stream = params->stream;
pipe->p_params->format = params->format;
} else { } else {
memcpy(pipe->p_params, params, sizeof(*params)); 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 nhlt_specific_cfg *cfg;
struct skl *skl = get_skl_ctx(dai->dev); struct skl *skl = get_skl_ctx(dai->dev);
int link_type = skl_tplg_be_link_type(mconfig->dev_type); 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); 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*/ /* update the blob based on virtual bus_id*/
cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
params->s_fmt, params->ch, params->s_fmt, params->ch,
params->s_freq, params->stream); params->s_freq, params->stream,
dev_type);
if (cfg) { if (cfg) {
mconfig->formats_config.caps_size = cfg->size; mconfig->formats_config.caps_size = cfg->size;
mconfig->formats_config.caps = (u32 *) &cfg->caps; 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, static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
struct snd_soc_tplg_vendor_string_elem *str_elem, struct snd_soc_tplg_vendor_string_elem *str_elem,
struct skl_dfw_manifest *minfo) struct skl *skl)
{ {
int tkn_count = 0; int tkn_count = 0;
static int ref_count; static int ref_count;
switch (str_elem->token) { switch (str_elem->token) {
case SKL_TKN_STR_LIB_NAME: 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; ref_count = 0;
return -EINVAL; return -EINVAL;
} }
strncpy(minfo->lib[ref_count].name, str_elem->string, strncpy(skl->skl_sst->lib_info[ref_count].name,
ARRAY_SIZE(minfo->lib[ref_count].name)); str_elem->string,
ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
ref_count++; ref_count++;
tkn_count++; tkn_count++;
break; 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, static int skl_tplg_get_str_tkn(struct device *dev,
struct snd_soc_tplg_vendor_array *array, struct snd_soc_tplg_vendor_array *array,
struct skl_dfw_manifest *minfo) struct skl *skl)
{ {
int tkn_count = 0, ret; int tkn_count = 0, ret;
struct snd_soc_tplg_vendor_string_elem *str_elem; struct snd_soc_tplg_vendor_string_elem *str_elem;
str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
while (tkn_count < array->num_elems) { 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++; str_elem++;
if (ret < 0) 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, static int skl_tplg_get_int_tkn(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem, struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl_dfw_manifest *minfo) struct skl *skl)
{ {
int tkn_count = 0; int tkn_count = 0;
switch (tkn_elem->token) { switch (tkn_elem->token) {
case SKL_TKN_U32_LIB_COUNT: case SKL_TKN_U32_LIB_COUNT:
minfo->lib_count = tkn_elem->value; skl->skl_sst->lib_count = tkn_elem->value;
tkn_count++; tkn_count++;
break; break;
@ -2352,7 +2401,7 @@ static int skl_tplg_get_int_tkn(struct device *dev,
* type. * type.
*/ */
static int skl_tplg_get_manifest_tkn(struct device *dev, 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 block_size)
{ {
int tkn_count = 0, ret; int tkn_count = 0, ret;
@ -2368,7 +2417,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
off += array->size; off += array->size;
switch (array->type) { switch (array->type) {
case SND_SOC_TPLG_TUPLE_TYPE_STRING: 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) if (ret < 0)
return ret; return ret;
@ -2390,7 +2439,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev,
while (tkn_count <= array->num_elems - 1) { while (tkn_count <= array->num_elems - 1) {
ret = skl_tplg_get_int_tkn(dev, ret = skl_tplg_get_int_tkn(dev,
tkn_elem, minfo); tkn_elem, skl);
if (ret < 0) if (ret < 0)
return ret; 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. * preceded by descriptors for type and size of data block.
*/ */
static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, 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; struct snd_soc_tplg_vendor_array *array;
int num_blocks, block_size = 0, block_type, off = 0; 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); data = (manifest->priv.data + off);
if (block_type == SKL_TYPE_TUPLE) { 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); block_size);
if (ret < 0) 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, static int skl_manifest_load(struct snd_soc_component *cmpnt,
struct snd_soc_tplg_manifest *manifest) struct snd_soc_tplg_manifest *manifest)
{ {
struct skl_dfw_manifest *minfo;
struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
struct skl *skl = ebus_to_skl(ebus); struct skl *skl = ebus_to_skl(ebus);
int ret = 0;
/* proceed only if we have private data defined */ /* proceed only if we have private data defined */
if (manifest->priv.size == 0) if (manifest->priv.size == 0)
return 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 (skl->skl_sst->lib_count > SKL_MAX_LIB) {
if (minfo->lib_count > HDA_MAX_LIB) {
dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
minfo->lib_count); skl->skl_sst->lib_count);
ret = -EINVAL; return -EINVAL;
} }
return ret; return 0;
} }
static struct snd_soc_tplg_ops skl_tplg_ops = { static struct snd_soc_tplg_ops skl_tplg_ops = {

View File

@ -254,6 +254,8 @@ struct skl_pipe_params {
u32 s_freq; u32 s_freq;
u32 s_fmt; u32 s_fmt;
u8 linktype; u8 linktype;
snd_pcm_format_t format;
int link_index;
int stream; int stream;
}; };
@ -332,6 +334,19 @@ struct skl_pipeline {
struct list_head node; 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) static inline struct skl *get_skl_ctx(struct device *dev)
{ {
struct hdac_ext_bus *ebus = dev_get_drvdata(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, struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai,
int stream); int stream);
enum skl_bitdepth skl_get_bit_depth(int params); 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 #endif

View File

@ -157,18 +157,6 @@ struct skl_dfw_algo_data {
char params[0]; char params[0];
} __packed; } __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 { enum skl_tkn_dir {
SKL_DIR_IN, SKL_DIR_IN,
SKL_DIR_OUT SKL_DIR_OUT

View File

@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci,
goto out_display_power_off; goto out_display_power_off;
} }
err = skl_nhlt_create_sysfs(skl);
if (err < 0)
goto out_nhlt_free;
skl_nhlt_update_topology_bin(skl); skl_nhlt_update_topology_bin(skl);
pci_set_drvdata(skl->pci, ebus); pci_set_drvdata(skl->pci, ebus);
@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci)
skl_free_dsp(skl); skl_free_dsp(skl);
skl_machine_device_unregister(skl); skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl); skl_dmic_device_unregister(skl);
skl_nhlt_remove_sysfs(skl);
skl_nhlt_free(skl->nhlt); skl_nhlt_free(skl->nhlt);
skl_free(ebus); skl_free(ebus);
dev_set_drvdata(&pci->dev, NULL); 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 */ /* PCI IDs */
static const struct pci_device_id skl_ids[] = { static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */ /* Sunrise Point-LP */
@ -889,6 +898,9 @@ static const struct pci_device_id skl_ids[] = {
/* KBL */ /* KBL */
{ PCI_DEVICE(0x8086, 0x9D71), { PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&sst_kbl_devdata}, .driver_data = (unsigned long)&sst_kbl_devdata},
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&sst_glk_devdata},
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, skl_ids); MODULE_DEVICE_TABLE(pci, skl_ids);

View File

@ -118,7 +118,8 @@ int skl_platform_register(struct device *dev);
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); struct nhlt_acpi_table *skl_nhlt_init(struct device *dev);
void skl_nhlt_free(struct nhlt_acpi_table *addr); void skl_nhlt_free(struct nhlt_acpi_table *addr);
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, 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_get_dmic_geo(struct skl *skl);
int skl_nhlt_update_topology_bin(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); void skl_cleanup_resources(struct skl *skl);
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
void skl_update_d0i3c(struct device *dev, bool enable); 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 */ #endif /* __SOUND_SOC_SKL_H */

Some files were not shown because too many files have changed in this diff Show More