diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 11:51:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 11:51:59 -0500 |
commit | a323ae93a74f669d890926187c68c711895e3454 (patch) | |
tree | 9a4ab8ed7bb98dc4321606332a883834ef7c8f6f /sound/soc/intel | |
parent | 3e63430a5cc26bc90a6e33ab33f901196b7b63ac (diff) | |
parent | 0e806151e86be52caa1349fa490eab8f09a2b6f5 (diff) |
Merge tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"In this batch, you can find lots of cleanups through the whole
subsystem, as our good New Year's resolution. Lots of LOCs and
commits are about LINE6 driver that was promoted finally from staging
tree, and as usual, there've been widely spread ASoC changes.
Here some highlights:
ALSA core changes
- Embedding struct device into ALSA core structures
- sequencer core cleanups / fixes
- PCM msbits constraints cleanups / fixes
- New SNDRV_PCM_TRIGGER_DRAIN command
- PCM kerneldoc fixes, header cleanups
- PCM code cleanups using more standard codes
- Control notification ID fixes
Driver cleanups
- Cleanups of PCI PM callbacks
- Timer helper usages cleanups
- Simplification (e.g. argument reduction) of many driver codes
HD-audio
- Hotkey and LED support on HP laptops with Realtek codecs
- Dock station support on HP laptops
- Toshiba Satellite S50D fixup
- Enhanced wallclock timestamp handling for HD-audio
- Componentization to simplify the linkage between i915 and hd-audio
drivers for Intel HDMI/DP
USB-audio
- Akai MPC Element support
- Enhanced timestamp handling
ASoC
- Lots of refactoringin ASoC core, moving drivers to more data driven
initialization and rationalizing a lot of DAPM usage
- Much improved handling of CDCLK clocks on Samsung I2S controllers
- Lots of driver specific cleanups and feature improvements
- CODEC support for TI PCM514x and TLV320AIC3104 devices
- Board support for Tegra systems with Realtek RT5677
- New driver for Maxim max98357a
- More enhancements / fixes for Intel SST driver
Others
- Promotion of LINE6 driver from staging along with lots of rewrites
and cleanups
- DT support for old non-ASoC atmel driver
- oxygen cleanups, XIO2001 init, Studio Evolution SE6x support
- Emu8000 DRAM size detection fix on ISA(!!) AWE64 boards
- A few more ak411x fixes for ice1724 boards"
* tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (542 commits)
ALSA: line6: toneport: Use explicit type for firmware version
ALSA: line6: Use explicit type for serial number
ALSA: line6: Return EIO if read/write not successful
ALSA: line6: Return error if device not responding
ALSA: line6: Add delay before reading status
ASoC: Intel: Clean data after SST fw fetch
ALSA: hda - Add docking station support for another HP machine
ALSA: control: fix failure to return new numerical ID in 'replace' event data
ALSA: usb: update trigger timestamp on first non-zero URB submitted
ALSA: hda: read trigger_timestamp immediately after starting DMA
ALSA: pcm: allow for trigger_tstamp snapshot in .trigger
ALSA: pcm: don't override timestamp unconditionally
ALSA: off by one bug in snd_riptide_joystick_probe()
ASoC: rt5670: Set use_single_rw flag for regmap
ASoC: rt286: Add rt288 codec support
ASoC: max98357a: Fix build in !CONFIG_OF case
ASoC: Intel: fix platform_no_drv_owner.cocci warnings
ARM: dts: Switch Odroid X2/U2 to simple-audio-card
ARM: dts: Exynos4 and Odroid X2/U3 sound device nodes update
ALSA: control: fix failure to return numerical ID in 'add' event
...
Diffstat (limited to 'sound/soc/intel')
-rw-r--r-- | sound/soc/intel/Kconfig | 15 | ||||
-rw-r--r-- | sound/soc/intel/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/intel/broadwell.c | 10 | ||||
-rw-r--r-- | sound/soc/intel/byt-rt5640.c | 12 | ||||
-rw-r--r-- | sound/soc/intel/bytcr_dpcm_rt5640.c | 1 | ||||
-rw-r--r-- | sound/soc/intel/cht_bsw_rt5645.c | 326 | ||||
-rw-r--r-- | sound/soc/intel/cht_bsw_rt5672.c | 15 | ||||
-rw-r--r-- | sound/soc/intel/sst-baytrail-pcm.c | 6 | ||||
-rw-r--r-- | sound/soc/intel/sst-dsp.c | 3 | ||||
-rw-r--r-- | sound/soc/intel/sst-firmware.c | 3 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-dsp.c | 17 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 177 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-ipc.h | 36 | ||||
-rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 232 | ||||
-rw-r--r-- | sound/soc/intel/sst-mfld-platform-pcm.c | 7 | ||||
-rw-r--r-- | sound/soc/intel/sst/sst.h | 3 | ||||
-rw-r--r-- | sound/soc/intel/sst/sst_acpi.c | 9 | ||||
-rw-r--r-- | sound/soc/intel/sst/sst_loader.c | 3 |
18 files changed, 570 insertions, 307 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f86de1211b96..ee03dbdda235 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -46,7 +46,7 @@ config SND_SOC_INTEL_BAYTRAIL | |||
46 | 46 | ||
47 | config SND_SOC_INTEL_HASWELL_MACH | 47 | config SND_SOC_INTEL_HASWELL_MACH |
48 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | 48 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" |
49 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\ | 49 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ |
50 | I2C_DESIGNWARE_PLATFORM | 50 | I2C_DESIGNWARE_PLATFORM |
51 | select SND_SOC_INTEL_HASWELL | 51 | select SND_SOC_INTEL_HASWELL |
52 | select SND_SOC_RT5640 | 52 | select SND_SOC_RT5640 |
@@ -76,7 +76,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
76 | 76 | ||
77 | config SND_SOC_INTEL_BROADWELL_MACH | 77 | config SND_SOC_INTEL_BROADWELL_MACH |
78 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | 78 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" |
79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\ | 79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ |
80 | I2C_DESIGNWARE_PLATFORM | 80 | I2C_DESIGNWARE_PLATFORM |
81 | select SND_SOC_INTEL_HASWELL | 81 | select SND_SOC_INTEL_HASWELL |
82 | select SND_COMPRESS_OFFLOAD | 82 | select SND_COMPRESS_OFFLOAD |
@@ -110,3 +110,14 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | |||
110 | platforms with RT5672 audio codec. | 110 | platforms with RT5672 audio codec. |
111 | Say Y if you have such a device | 111 | Say Y if you have such a device |
112 | If unsure select "N". | 112 | If unsure select "N". |
113 | |||
114 | config SND_SOC_INTEL_CHT_BSW_RT5645_MACH | ||
115 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec" | ||
116 | depends on X86_INTEL_LPSS | ||
117 | select SND_SOC_RT5645 | ||
118 | select SND_SST_MFLD_PLATFORM | ||
119 | select SND_SST_IPC_ACPI | ||
120 | help | ||
121 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | ||
122 | platforms with RT5645 audio codec. | ||
123 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index e928ec385300..a8e53c45c6b6 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -28,6 +28,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | |||
28 | snd-soc-sst-broadwell-objs := broadwell.o | 28 | snd-soc-sst-broadwell-objs := broadwell.o |
29 | snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o | 29 | snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o |
30 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | 30 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o |
31 | snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o | ||
31 | 32 | ||
32 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 33 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
33 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 34 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | |||
35 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 36 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
36 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o | 37 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o |
37 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | 38 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o |
39 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o | ||
38 | 40 | ||
39 | # DSP driver | 41 | # DSP driver |
40 | obj-$(CONFIG_SND_SST_IPC) += sst/ | 42 | obj-$(CONFIG_SND_SST_IPC) += sst/ |
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 7cf95d5d5d80..9cf7d01479ad 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c | |||
@@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = { | |||
140 | 140 | ||
141 | static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | 141 | static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) |
142 | { | 142 | { |
143 | struct snd_soc_codec *codec = rtd->codec; | ||
144 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
145 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | 143 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); |
146 | struct sst_hsw *broadwell = pdata->dsp; | 144 | struct sst_hsw *broadwell = pdata->dsp; |
147 | int ret; | 145 | int ret; |
@@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | |||
155 | return ret; | 153 | return ret; |
156 | } | 154 | } |
157 | 155 | ||
158 | /* always connected - check HP for jack detect */ | ||
159 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | ||
160 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | ||
161 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | ||
162 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | ||
163 | snd_soc_dapm_enable_pin(dapm, "DMIC1"); | ||
164 | snd_soc_dapm_enable_pin(dapm, "DMIC2"); | ||
165 | |||
166 | return 0; | 156 | return 0; |
167 | } | 157 | } |
168 | 158 | ||
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 0cba7830c5e9..354eaad886e1 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c | |||
@@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
132 | { | 132 | { |
133 | int ret; | 133 | int ret; |
134 | struct snd_soc_codec *codec = runtime->codec; | 134 | struct snd_soc_codec *codec = runtime->codec; |
135 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
136 | struct snd_soc_card *card = runtime->card; | 135 | struct snd_soc_card *card = runtime->card; |
137 | const struct snd_soc_dapm_route *custom_map; | 136 | const struct snd_soc_dapm_route *custom_map; |
138 | int num_routes; | 137 | int num_routes; |
@@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
161 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); | 160 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); |
162 | } | 161 | } |
163 | 162 | ||
164 | ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); | 163 | ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); |
165 | if (ret) | 164 | if (ret) |
166 | return ret; | 165 | return ret; |
167 | 166 | ||
@@ -171,13 +170,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
171 | return ret; | 170 | return ret; |
172 | } | 171 | } |
173 | 172 | ||
174 | snd_soc_dapm_ignore_suspend(dapm, "HPOL"); | 173 | snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); |
175 | snd_soc_dapm_ignore_suspend(dapm, "HPOR"); | 174 | snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); |
176 | |||
177 | snd_soc_dapm_ignore_suspend(dapm, "SPOLP"); | ||
178 | snd_soc_dapm_ignore_suspend(dapm, "SPOLN"); | ||
179 | snd_soc_dapm_ignore_suspend(dapm, "SPORP"); | ||
180 | snd_soc_dapm_ignore_suspend(dapm, "SPORN"); | ||
181 | 175 | ||
182 | return ret; | 176 | return ret; |
183 | } | 177 | } |
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index eef0c56ec32e..59308629043e 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c | |||
@@ -215,7 +215,6 @@ static int snd_byt_mc_probe(struct platform_device *pdev) | |||
215 | 215 | ||
216 | static struct platform_driver snd_byt_mc_driver = { | 216 | static struct platform_driver snd_byt_mc_driver = { |
217 | .driver = { | 217 | .driver = { |
218 | .owner = THIS_MODULE, | ||
219 | .name = "bytt100_rt5640", | 218 | .name = "bytt100_rt5640", |
220 | .pm = &snd_soc_pm_ops, | 219 | .pm = &snd_soc_pm_ops, |
221 | }, | 220 | }, |
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c new file mode 100644 index 000000000000..bd29617a9ab9 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5645.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms | ||
3 | * Cherrytrail and Braswell, with RT5645 codec. | ||
4 | * | ||
5 | * Copyright (C) 2015 Intel Corp | ||
6 | * Author: Fang, Yang A <yang.a.fang@intel.com> | ||
7 | * N,Harshapriya <harshapriya.n@intel.com> | ||
8 | * This file is modified from cht_bsw_rt5672.c | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/jack.h> | ||
30 | #include "../codecs/rt5645.h" | ||
31 | #include "sst-atom-controls.h" | ||
32 | |||
33 | #define CHT_PLAT_CLK_3_HZ 19200000 | ||
34 | #define CHT_CODEC_DAI "rt5645-aif1" | ||
35 | |||
36 | struct cht_mc_private { | ||
37 | struct snd_soc_jack hp_jack; | ||
38 | struct snd_soc_jack mic_jack; | ||
39 | }; | ||
40 | |||
41 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | ||
42 | { | ||
43 | int i; | ||
44 | |||
45 | for (i = 0; i < card->num_rtd; i++) { | ||
46 | struct snd_soc_pcm_runtime *rtd; | ||
47 | |||
48 | rtd = card->rtd + i; | ||
49 | if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, | ||
50 | strlen(CHT_CODEC_DAI))) | ||
51 | return rtd->codec_dai; | ||
52 | } | ||
53 | return NULL; | ||
54 | } | ||
55 | |||
56 | static int platform_clock_control(struct snd_soc_dapm_widget *w, | ||
57 | struct snd_kcontrol *k, int event) | ||
58 | { | ||
59 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
60 | struct snd_soc_card *card = dapm->card; | ||
61 | struct snd_soc_dai *codec_dai; | ||
62 | int ret; | ||
63 | |||
64 | codec_dai = cht_get_codec_dai(card); | ||
65 | if (!codec_dai) { | ||
66 | dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); | ||
67 | return -EIO; | ||
68 | } | ||
69 | |||
70 | if (!SND_SOC_DAPM_EVENT_OFF(event)) | ||
71 | return 0; | ||
72 | |||
73 | /* Set codec sysclk source to its internal clock because codec PLL will | ||
74 | * be off when idle and MCLK will also be off by ACPI when codec is | ||
75 | * runtime suspended. Codec needs clock for jack detection and button | ||
76 | * press. | ||
77 | */ | ||
78 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, | ||
79 | 0, SND_SOC_CLOCK_IN); | ||
80 | if (ret < 0) { | ||
81 | dev_err(card->dev, "can't set codec sysclk: %d\n", ret); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | ||
89 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
90 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
91 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
92 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
93 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | ||
94 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | ||
95 | }; | ||
96 | |||
97 | static const struct snd_soc_dapm_route cht_audio_map[] = { | ||
98 | {"IN1P", NULL, "Headset Mic"}, | ||
99 | {"IN1N", NULL, "Headset Mic"}, | ||
100 | {"DMIC L1", NULL, "Int Mic"}, | ||
101 | {"DMIC R1", NULL, "Int Mic"}, | ||
102 | {"Headphone", NULL, "HPOL"}, | ||
103 | {"Headphone", NULL, "HPOR"}, | ||
104 | {"Ext Spk", NULL, "SPOL"}, | ||
105 | {"Ext Spk", NULL, "SPOR"}, | ||
106 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
107 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
108 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
109 | {"codec_in0", NULL, "ssp2 Rx" }, | ||
110 | {"codec_in1", NULL, "ssp2 Rx" }, | ||
111 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
112 | {"Headphone", NULL, "Platform Clock"}, | ||
113 | {"Headset Mic", NULL, "Platform Clock"}, | ||
114 | {"Int Mic", NULL, "Platform Clock"}, | ||
115 | {"Ext Spk", NULL, "Platform Clock"}, | ||
116 | }; | ||
117 | |||
118 | static const struct snd_kcontrol_new cht_mc_controls[] = { | ||
119 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
120 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
121 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
122 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
123 | }; | ||
124 | |||
125 | static int cht_aif1_hw_params(struct snd_pcm_substream *substream, | ||
126 | struct snd_pcm_hw_params *params) | ||
127 | { | ||
128 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
129 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
130 | int ret; | ||
131 | |||
132 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ | ||
133 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK, | ||
134 | CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); | ||
135 | if (ret < 0) { | ||
136 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1, | ||
141 | params_rate(params) * 512, SND_SOC_CLOCK_IN); | ||
142 | if (ret < 0) { | ||
143 | dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | ||
151 | { | ||
152 | int ret; | ||
153 | struct snd_soc_codec *codec = runtime->codec; | ||
154 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | ||
155 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); | ||
156 | |||
157 | /* Select clk_i2s1_asrc as ASRC clock source */ | ||
158 | rt5645_sel_asrc_clk_src(codec, | ||
159 | RT5645_DA_STEREO_FILTER | | ||
160 | RT5645_DA_MONO_L_FILTER | | ||
161 | RT5645_DA_MONO_R_FILTER | | ||
162 | RT5645_AD_STEREO_FILTER, | ||
163 | RT5645_CLK_SEL_I2S1_ASRC); | ||
164 | |||
165 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ | ||
166 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); | ||
167 | if (ret < 0) { | ||
168 | dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | ret = snd_soc_jack_new(codec, "Headphone Jack", | ||
173 | SND_JACK_HEADPHONE, | ||
174 | &ctx->hp_jack); | ||
175 | if (ret) { | ||
176 | dev_err(runtime->dev, "HP jack creation failed %d\n", ret); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | ret = snd_soc_jack_new(codec, "Mic Jack", | ||
181 | SND_JACK_MICROPHONE, | ||
182 | &ctx->mic_jack); | ||
183 | if (ret) { | ||
184 | dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack); | ||
189 | |||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
194 | struct snd_pcm_hw_params *params) | ||
195 | { | ||
196 | struct snd_interval *rate = hw_param_interval(params, | ||
197 | SNDRV_PCM_HW_PARAM_RATE); | ||
198 | struct snd_interval *channels = hw_param_interval(params, | ||
199 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
200 | |||
201 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
202 | rate->min = rate->max = 48000; | ||
203 | channels->min = channels->max = 2; | ||
204 | |||
205 | /* set SSP2 to 24-bit */ | ||
206 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
207 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
208 | SNDRV_PCM_FORMAT_S24_LE); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static unsigned int rates_48000[] = { | ||
213 | 48000, | ||
214 | }; | ||
215 | |||
216 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
217 | .count = ARRAY_SIZE(rates_48000), | ||
218 | .list = rates_48000, | ||
219 | }; | ||
220 | |||
221 | static int cht_aif1_startup(struct snd_pcm_substream *substream) | ||
222 | { | ||
223 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
224 | SNDRV_PCM_HW_PARAM_RATE, | ||
225 | &constraints_48000); | ||
226 | } | ||
227 | |||
228 | static struct snd_soc_ops cht_aif1_ops = { | ||
229 | .startup = cht_aif1_startup, | ||
230 | }; | ||
231 | |||
232 | static struct snd_soc_ops cht_be_ssp2_ops = { | ||
233 | .hw_params = cht_aif1_hw_params, | ||
234 | }; | ||
235 | |||
236 | static struct snd_soc_dai_link cht_dailink[] = { | ||
237 | [MERR_DPCM_AUDIO] = { | ||
238 | .name = "Audio Port", | ||
239 | .stream_name = "Audio", | ||
240 | .cpu_dai_name = "media-cpu-dai", | ||
241 | .codec_dai_name = "snd-soc-dummy-dai", | ||
242 | .codec_name = "snd-soc-dummy", | ||
243 | .platform_name = "sst-mfld-platform", | ||
244 | .ignore_suspend = 1, | ||
245 | .dynamic = 1, | ||
246 | .dpcm_playback = 1, | ||
247 | .dpcm_capture = 1, | ||
248 | .ops = &cht_aif1_ops, | ||
249 | }, | ||
250 | [MERR_DPCM_COMPR] = { | ||
251 | .name = "Compressed Port", | ||
252 | .stream_name = "Compress", | ||
253 | .cpu_dai_name = "compress-cpu-dai", | ||
254 | .codec_dai_name = "snd-soc-dummy-dai", | ||
255 | .codec_name = "snd-soc-dummy", | ||
256 | .platform_name = "sst-mfld-platform", | ||
257 | }, | ||
258 | /* CODEC<->CODEC link */ | ||
259 | /* back ends */ | ||
260 | { | ||
261 | .name = "SSP2-Codec", | ||
262 | .be_id = 1, | ||
263 | .cpu_dai_name = "ssp2-port", | ||
264 | .platform_name = "sst-mfld-platform", | ||
265 | .no_pcm = 1, | ||
266 | .codec_dai_name = "rt5645-aif1", | ||
267 | .codec_name = "i2c-10EC5645:00", | ||
268 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | ||
269 | | SND_SOC_DAIFMT_CBS_CFS, | ||
270 | .init = cht_codec_init, | ||
271 | .be_hw_params_fixup = cht_codec_fixup, | ||
272 | .ignore_suspend = 1, | ||
273 | .dpcm_playback = 1, | ||
274 | .dpcm_capture = 1, | ||
275 | .ops = &cht_be_ssp2_ops, | ||
276 | }, | ||
277 | }; | ||
278 | |||
279 | /* SoC card */ | ||
280 | static struct snd_soc_card snd_soc_card_cht = { | ||
281 | .name = "chtrt5645", | ||
282 | .dai_link = cht_dailink, | ||
283 | .num_links = ARRAY_SIZE(cht_dailink), | ||
284 | .dapm_widgets = cht_dapm_widgets, | ||
285 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | ||
286 | .dapm_routes = cht_audio_map, | ||
287 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | ||
288 | .controls = cht_mc_controls, | ||
289 | .num_controls = ARRAY_SIZE(cht_mc_controls), | ||
290 | }; | ||
291 | |||
292 | static int snd_cht_mc_probe(struct platform_device *pdev) | ||
293 | { | ||
294 | int ret_val = 0; | ||
295 | struct cht_mc_private *drv; | ||
296 | |||
297 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); | ||
298 | if (!drv) | ||
299 | return -ENOMEM; | ||
300 | |||
301 | snd_soc_card_cht.dev = &pdev->dev; | ||
302 | snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); | ||
303 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | ||
304 | if (ret_val) { | ||
305 | dev_err(&pdev->dev, | ||
306 | "snd_soc_register_card failed %d\n", ret_val); | ||
307 | return ret_val; | ||
308 | } | ||
309 | platform_set_drvdata(pdev, &snd_soc_card_cht); | ||
310 | return ret_val; | ||
311 | } | ||
312 | |||
313 | static struct platform_driver snd_cht_mc_driver = { | ||
314 | .driver = { | ||
315 | .name = "cht-bsw-rt5645", | ||
316 | .pm = &snd_soc_pm_ops, | ||
317 | }, | ||
318 | .probe = snd_cht_mc_probe, | ||
319 | }; | ||
320 | |||
321 | module_platform_driver(snd_cht_mc_driver) | ||
322 | |||
323 | MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver"); | ||
324 | MODULE_AUTHOR("Fang, Yang A,N,Harshapriya"); | ||
325 | MODULE_LICENSE("GPL v2"); | ||
326 | MODULE_ALIAS("platform:cht-bsw-rt5645"); | ||
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index 9b8b561171b7..ff016621583a 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c | |||
@@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
140 | { | 140 | { |
141 | int ret; | 141 | int ret; |
142 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | 142 | struct snd_soc_dai *codec_dai = runtime->codec_dai; |
143 | struct snd_soc_codec *codec = codec_dai->codec; | ||
143 | 144 | ||
144 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ | 145 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ |
145 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); | 146 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); |
@@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
148 | return ret; | 149 | return ret; |
149 | } | 150 | } |
150 | 151 | ||
152 | /* Select codec ASRC clock source to track I2S1 clock, because codec | ||
153 | * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot | ||
154 | * be supported by RT5672. Otherwise, ASRC will be disabled and cause | ||
155 | * noise. | ||
156 | */ | ||
157 | rt5670_sel_asrc_clk_src(codec, | ||
158 | RT5670_DA_STEREO_FILTER | ||
159 | | RT5670_DA_MONO_L_FILTER | ||
160 | | RT5670_DA_MONO_R_FILTER | ||
161 | | RT5670_AD_STEREO_FILTER | ||
162 | | RT5670_AD_MONO_L_FILTER | ||
163 | | RT5670_AD_MONO_R_FILTER, | ||
164 | RT5670_CLK_SEL_I2S1_ASRC); | ||
151 | return 0; | 165 | return 0; |
152 | } | 166 | } |
153 | 167 | ||
@@ -270,7 +284,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
270 | 284 | ||
271 | static struct platform_driver snd_cht_mc_driver = { | 285 | static struct platform_driver snd_cht_mc_driver = { |
272 | .driver = { | 286 | .driver = { |
273 | .owner = THIS_MODULE, | ||
274 | .name = "cht-bsw-rt5672", | 287 | .name = "cht-bsw-rt5672", |
275 | .pm = &snd_soc_pm_ops, | 288 | .pm = &snd_soc_pm_ops, |
276 | }, | 289 | }, |
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 3bb6288d8b4d..224c49c9f135 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c | |||
@@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = { | |||
320 | .mmap = sst_byt_pcm_mmap, | 320 | .mmap = sst_byt_pcm_mmap, |
321 | }; | 321 | }; |
322 | 322 | ||
323 | static void sst_byt_pcm_free(struct snd_pcm *pcm) | ||
324 | { | ||
325 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
326 | } | ||
327 | |||
328 | static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) | 323 | static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) |
329 | { | 324 | { |
330 | struct snd_pcm *pcm = rtd->pcm; | 325 | struct snd_pcm *pcm = rtd->pcm; |
@@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = { | |||
403 | .remove = sst_byt_pcm_remove, | 398 | .remove = sst_byt_pcm_remove, |
404 | .ops = &sst_byt_pcm_ops, | 399 | .ops = &sst_byt_pcm_ops, |
405 | .pcm_new = sst_byt_pcm_new, | 400 | .pcm_new = sst_byt_pcm_new, |
406 | .pcm_free = sst_byt_pcm_free, | ||
407 | }; | 401 | }; |
408 | 402 | ||
409 | static const struct snd_soc_component_driver byt_dai_component = { | 403 | static const struct snd_soc_component_driver byt_dai_component = { |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 86e410845670..64e94212d2d2 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
@@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst) | |||
410 | if (sst->ops->free) | 410 | if (sst->ops->free) |
411 | sst->ops->free(sst); | 411 | sst->ops->free(sst); |
412 | 412 | ||
413 | if (sst->dma) | 413 | sst_dma_free(sst->dma); |
414 | sst_dma_free(sst->dma); | ||
415 | } | 414 | } |
416 | EXPORT_SYMBOL_GPL(sst_dsp_free); | 415 | EXPORT_SYMBOL_GPL(sst_dsp_free); |
417 | 416 | ||
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index b3f9489794a6..5f71ef607a57 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c | |||
@@ -497,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, | |||
497 | sst_module->sst_fw = sst_fw; | 497 | sst_module->sst_fw = sst_fw; |
498 | sst_module->scratch_size = template->scratch_size; | 498 | sst_module->scratch_size = template->scratch_size; |
499 | sst_module->persistent_size = template->persistent_size; | 499 | sst_module->persistent_size = template->persistent_size; |
500 | sst_module->entry = template->entry; | ||
500 | 501 | ||
501 | INIT_LIST_HEAD(&sst_module->block_list); | 502 | INIT_LIST_HEAD(&sst_module->block_list); |
502 | INIT_LIST_HEAD(&sst_module->runtime_list); | 503 | INIT_LIST_HEAD(&sst_module->runtime_list); |
@@ -790,6 +791,7 @@ int sst_module_alloc_blocks(struct sst_module *module) | |||
790 | struct sst_block_allocator ba; | 791 | struct sst_block_allocator ba; |
791 | int ret; | 792 | int ret; |
792 | 793 | ||
794 | memset(&ba, 0, sizeof(ba)); | ||
793 | ba.size = module->size; | 795 | ba.size = module->size; |
794 | ba.type = module->type; | 796 | ba.type = module->type; |
795 | ba.offset = module->offset; | 797 | ba.offset = module->offset; |
@@ -863,6 +865,7 @@ int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, | |||
863 | if (module->persistent_size == 0) | 865 | if (module->persistent_size == 0) |
864 | return 0; | 866 | return 0; |
865 | 867 | ||
868 | memset(&ba, 0, sizeof(ba)); | ||
866 | ba.size = module->persistent_size; | 869 | ba.size = module->persistent_size; |
867 | ba.type = SST_MEM_DRAM; | 870 | ba.type = SST_MEM_DRAM; |
868 | 871 | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 57039b00efc2..c42ffae5fe9f 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
@@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst) | |||
306 | static int hsw_set_dsp_D0(struct sst_dsp *sst) | 306 | static int hsw_set_dsp_D0(struct sst_dsp *sst) |
307 | { | 307 | { |
308 | int tries = 10; | 308 | int tries = 10; |
309 | u32 reg; | 309 | u32 reg, fw_dump_bit; |
310 | 310 | ||
311 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | 311 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ |
312 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | 312 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); |
@@ -368,7 +368,9 @@ finish: | |||
368 | can't be accessed, please enable each block before accessing. */ | 368 | can't be accessed, please enable each block before accessing. */ |
369 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 369 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
370 | reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; | 370 | reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; |
371 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); | 371 | /* for D0, always enable the block(DSRAM[0]) used for FW dump */ |
372 | fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; | ||
373 | writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
372 | 374 | ||
373 | 375 | ||
374 | /* disable DMA finish function for SSP0 & SSP1 */ | 376 | /* disable DMA finish function for SSP0 & SSP1 */ |
@@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = { | |||
491 | {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ | 493 | {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ |
492 | {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ | 494 | {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ |
493 | }; | 495 | }; |
496 | |||
494 | static u32 hsw_block_get_bit(struct sst_mem_block *block) | 497 | static u32 hsw_block_get_bit(struct sst_mem_block *block) |
495 | { | 498 | { |
496 | u32 bit = 0, shift = 0, index; | 499 | u32 bit = 0, shift = 0, index; |
@@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block) | |||
587 | 590 | ||
588 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 591 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
589 | bit = hsw_block_get_bit(block); | 592 | bit = hsw_block_get_bit(block); |
590 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | 593 | /* don't disable DSRAM[0], keep it always enable for FW dump*/ |
594 | if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT)) | ||
595 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
591 | 596 | ||
592 | /* wait 18 DSP clock ticks */ | 597 | /* wait 18 DSP clock ticks */ |
593 | udelay(10); | 598 | udelay(10); |
@@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
612 | const struct sst_adsp_memregion *region; | 617 | const struct sst_adsp_memregion *region; |
613 | struct device *dev; | 618 | struct device *dev; |
614 | int ret = -ENODEV, i, j, region_count; | 619 | int ret = -ENODEV, i, j, region_count; |
615 | u32 offset, size; | 620 | u32 offset, size, fw_dump_bit; |
616 | 621 | ||
617 | dev = sst->dma_dev; | 622 | dev = sst->dma_dev; |
618 | 623 | ||
@@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
669 | } | 674 | } |
670 | } | 675 | } |
671 | 676 | ||
677 | /* always enable the block(DSRAM[0]) used for FW dump */ | ||
678 | fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; | ||
672 | /* set default power gating control, enable power gating control for all blocks. that is, | 679 | /* set default power gating control, enable power gating control for all blocks. that is, |
673 | can't be accessed, please enable each block before accessing. */ | 680 | can't be accessed, please enable each block before accessing. */ |
674 | writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0); | 681 | writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); |
675 | 682 | ||
676 | return 0; | 683 | return 0; |
677 | } | 684 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 8156cc1accb7..394af5684c05 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <sound/asound.h> | ||
34 | 35 | ||
35 | #include "sst-haswell-ipc.h" | 36 | #include "sst-haswell-ipc.h" |
36 | #include "sst-dsp.h" | 37 | #include "sst-dsp.h" |
@@ -94,6 +95,8 @@ | |||
94 | /* Mailbox */ | 95 | /* Mailbox */ |
95 | #define IPC_MAX_MAILBOX_BYTES 256 | 96 | #define IPC_MAX_MAILBOX_BYTES 256 |
96 | 97 | ||
98 | #define INVALID_STREAM_HW_ID 0xffffffff | ||
99 | |||
97 | /* Global Message - Types and Replies */ | 100 | /* Global Message - Types and Replies */ |
98 | enum ipc_glb_type { | 101 | enum ipc_glb_type { |
99 | IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ | 102 | IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ |
@@ -240,6 +243,9 @@ struct sst_hsw_stream { | |||
240 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data); | 243 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data); |
241 | void *pdata; | 244 | void *pdata; |
242 | 245 | ||
246 | /* record the fw read position when playback */ | ||
247 | snd_pcm_uframes_t old_position; | ||
248 | bool play_silence; | ||
243 | struct list_head node; | 249 | struct list_head node; |
244 | }; | 250 | }; |
245 | 251 | ||
@@ -275,7 +281,6 @@ struct sst_hsw { | |||
275 | /* FW config */ | 281 | /* FW config */ |
276 | struct sst_hsw_ipc_fw_ready fw_ready; | 282 | struct sst_hsw_ipc_fw_ready fw_ready; |
277 | struct sst_hsw_ipc_fw_version version; | 283 | struct sst_hsw_ipc_fw_version version; |
278 | struct sst_module *scratch; | ||
279 | bool fw_done; | 284 | bool fw_done; |
280 | struct sst_fw *sst_fw; | 285 | struct sst_fw *sst_fw; |
281 | 286 | ||
@@ -337,12 +342,6 @@ static inline u32 msg_get_stage_type(u32 msg) | |||
337 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | 342 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; |
338 | } | 343 | } |
339 | 344 | ||
340 | static inline u32 msg_set_stage_type(u32 msg, u32 type) | ||
341 | { | ||
342 | return (msg & ~IPC_STG_TYPE_MASK) + | ||
343 | (type << IPC_STG_TYPE_SHIFT); | ||
344 | } | ||
345 | |||
346 | static inline u32 msg_get_stream_id(u32 msg) | 345 | static inline u32 msg_get_stream_id(u32 msg) |
347 | { | 346 | { |
348 | return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; | 347 | return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; |
@@ -969,45 +968,6 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, | |||
969 | } | 968 | } |
970 | 969 | ||
971 | /* Mixer Controls */ | 970 | /* Mixer Controls */ |
972 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
973 | u32 stage_id, u32 channel) | ||
974 | { | ||
975 | int ret; | ||
976 | |||
977 | ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel, | ||
978 | &stream->mute_volume[channel]); | ||
979 | if (ret < 0) | ||
980 | return ret; | ||
981 | |||
982 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0); | ||
983 | if (ret < 0) { | ||
984 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
985 | stream->reply.stream_hw_id, channel); | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | stream->mute[channel] = 1; | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
994 | u32 stage_id, u32 channel) | ||
995 | |||
996 | { | ||
997 | int ret; | ||
998 | |||
999 | stream->mute[channel] = 0; | ||
1000 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, | ||
1001 | stream->mute_volume[channel]); | ||
1002 | if (ret < 0) { | ||
1003 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
1004 | stream->reply.stream_hw_id, channel); | ||
1005 | return ret; | ||
1006 | } | ||
1007 | |||
1008 | return 0; | ||
1009 | } | ||
1010 | |||
1011 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | 971 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, |
1012 | u32 stage_id, u32 channel, u32 *volume) | 972 | u32 stage_id, u32 channel, u32 *volume) |
1013 | { | 973 | { |
@@ -1021,17 +981,6 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream | |||
1021 | return 0; | 981 | return 0; |
1022 | } | 982 | } |
1023 | 983 | ||
1024 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
1025 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
1026 | enum sst_hsw_volume_curve curve) | ||
1027 | { | ||
1028 | /* curve duration in steps of 100ns */ | ||
1029 | stream->vol_req.curve_duration = curve_duration; | ||
1030 | stream->vol_req.curve_type = curve; | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | /* stream volume */ | 984 | /* stream volume */ |
1036 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | 985 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, |
1037 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) | 986 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) |
@@ -1083,42 +1032,6 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1083 | return 0; | 1032 | return 0; |
1084 | } | 1033 | } |
1085 | 1034 | ||
1086 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
1087 | { | ||
1088 | int ret; | ||
1089 | |||
1090 | ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel, | ||
1091 | &hsw->mute_volume[channel]); | ||
1092 | if (ret < 0) | ||
1093 | return ret; | ||
1094 | |||
1095 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0); | ||
1096 | if (ret < 0) { | ||
1097 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
1098 | channel); | ||
1099 | return ret; | ||
1100 | } | ||
1101 | |||
1102 | hsw->mute[channel] = 1; | ||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
1107 | { | ||
1108 | int ret; | ||
1109 | |||
1110 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, | ||
1111 | hsw->mixer_info.volume_register_address[channel]); | ||
1112 | if (ret < 0) { | ||
1113 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
1114 | channel); | ||
1115 | return ret; | ||
1116 | } | ||
1117 | |||
1118 | hsw->mute[channel] = 0; | ||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | 1035 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, |
1123 | u32 *volume) | 1036 | u32 *volume) |
1124 | { | 1037 | { |
@@ -1132,16 +1045,6 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1132 | return 0; | 1045 | return 0; |
1133 | } | 1046 | } |
1134 | 1047 | ||
1135 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
1136 | u64 curve_duration, enum sst_hsw_volume_curve curve) | ||
1137 | { | ||
1138 | /* curve duration in steps of 100ns */ | ||
1139 | hsw->curve_duration = curve_duration; | ||
1140 | hsw->curve_type = curve; | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* global mixer volume */ | 1048 | /* global mixer volume */ |
1146 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | 1049 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, |
1147 | u32 volume) | 1050 | u32 volume) |
@@ -1208,6 +1111,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
1208 | return NULL; | 1111 | return NULL; |
1209 | 1112 | ||
1210 | spin_lock_irqsave(&sst->spinlock, flags); | 1113 | spin_lock_irqsave(&sst->spinlock, flags); |
1114 | stream->reply.stream_hw_id = INVALID_STREAM_HW_ID; | ||
1211 | list_add(&stream->node, &hsw->stream_list); | 1115 | list_add(&stream->node, &hsw->stream_list); |
1212 | stream->notify_position = notify_position; | 1116 | stream->notify_position = notify_position; |
1213 | stream->pdata = data; | 1117 | stream->pdata = data; |
@@ -1447,50 +1351,32 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1447 | return 0; | 1351 | return 0; |
1448 | } | 1352 | } |
1449 | 1353 | ||
1450 | /* Stream Information - these calls could be inline but we want the IPC | 1354 | snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw, |
1451 | ABI to be opaque to client PCM drivers to cope with any future ABI changes */ | ||
1452 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | ||
1453 | struct sst_hsw_stream *stream) | 1355 | struct sst_hsw_stream *stream) |
1454 | { | 1356 | { |
1455 | return stream->reply.stream_hw_id; | 1357 | return stream->old_position; |
1456 | } | 1358 | } |
1457 | 1359 | ||
1458 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | 1360 | void sst_hsw_stream_set_old_position(struct sst_hsw *hsw, |
1459 | struct sst_hsw_stream *stream) | 1361 | struct sst_hsw_stream *stream, snd_pcm_uframes_t val) |
1460 | { | 1362 | { |
1461 | return stream->reply.mixer_hw_id; | 1363 | stream->old_position = val; |
1462 | } | 1364 | } |
1463 | 1365 | ||
1464 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | 1366 | bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw, |
1465 | struct sst_hsw_stream *stream) | 1367 | struct sst_hsw_stream *stream) |
1466 | { | 1368 | { |
1467 | return stream->reply.read_position_register_address; | 1369 | return stream->play_silence; |
1468 | } | ||
1469 | |||
1470 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | ||
1471 | struct sst_hsw_stream *stream) | ||
1472 | { | ||
1473 | return stream->reply.presentation_position_register_address; | ||
1474 | } | ||
1475 | |||
1476 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | ||
1477 | struct sst_hsw_stream *stream, u32 channel) | ||
1478 | { | ||
1479 | if (channel >= 2) | ||
1480 | return 0; | ||
1481 | |||
1482 | return stream->reply.peak_meter_register_address[channel]; | ||
1483 | } | 1370 | } |
1484 | 1371 | ||
1485 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | 1372 | void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, |
1486 | struct sst_hsw_stream *stream, u32 channel) | 1373 | struct sst_hsw_stream *stream, bool val) |
1487 | { | 1374 | { |
1488 | if (channel >= 2) | 1375 | stream->play_silence = val; |
1489 | return 0; | ||
1490 | |||
1491 | return stream->reply.volume_register_address[channel]; | ||
1492 | } | 1376 | } |
1493 | 1377 | ||
1378 | /* Stream Information - these calls could be inline but we want the IPC | ||
1379 | ABI to be opaque to client PCM drivers to cope with any future ABI changes */ | ||
1494 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw) | 1380 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw) |
1495 | { | 1381 | { |
1496 | struct sst_hsw_ipc_stream_info_reply *reply; | 1382 | struct sst_hsw_ipc_stream_info_reply *reply; |
@@ -1628,30 +1514,6 @@ u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, | |||
1628 | return ppos; | 1514 | return ppos; |
1629 | } | 1515 | } |
1630 | 1516 | ||
1631 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
1632 | struct sst_hsw_stream *stream, u32 stage_id, u32 position) | ||
1633 | { | ||
1634 | u32 header; | ||
1635 | int ret; | ||
1636 | |||
1637 | trace_stream_write_position(stream->reply.stream_hw_id, position); | ||
1638 | |||
1639 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
1640 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
1641 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | ||
1642 | header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT); | ||
1643 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
1644 | stream->wpos.position = position; | ||
1645 | |||
1646 | ret = ipc_tx_message_nowait(hsw, header, &stream->wpos, | ||
1647 | sizeof(stream->wpos)); | ||
1648 | if (ret < 0) | ||
1649 | dev_err(hsw->dev, "error: stream %d set position %d failed\n", | ||
1650 | stream->reply.stream_hw_id, position); | ||
1651 | |||
1652 | return ret; | ||
1653 | } | ||
1654 | |||
1655 | /* physical BE config */ | 1517 | /* physical BE config */ |
1656 | int sst_hsw_device_set_config(struct sst_hsw *hsw, | 1518 | int sst_hsw_device_set_config(struct sst_hsw *hsw, |
1657 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, | 1519 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, |
@@ -2132,7 +1994,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
2132 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | 1994 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, |
2133 | hsw->dx_context, hsw->dx_context_paddr); | 1995 | hsw->dx_context, hsw->dx_context_paddr); |
2134 | sst_dsp_free(hsw->dsp); | 1996 | sst_dsp_free(hsw->dsp); |
2135 | kfree(hsw->scratch); | ||
2136 | kthread_stop(hsw->tx_thread); | 1997 | kthread_stop(hsw->tx_thread); |
2137 | kfree(hsw->msg); | 1998 | kfree(hsw->msg); |
2138 | } | 1999 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 138e894ab413..858096041cb1 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <sound/asound.h> | ||
23 | 24 | ||
24 | #define SST_HSW_NO_CHANNELS 4 | 25 | #define SST_HSW_NO_CHANNELS 4 |
25 | #define SST_HSW_MAX_DX_REGIONS 14 | 26 | #define SST_HSW_MAX_DX_REGIONS 14 |
@@ -376,32 +377,17 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, | |||
376 | u32 create_channel_map(enum sst_hsw_channel_config config); | 377 | u32 create_channel_map(enum sst_hsw_channel_config config); |
377 | 378 | ||
378 | /* Stream Mixer Controls - */ | 379 | /* Stream Mixer Controls - */ |
379 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
380 | u32 stage_id, u32 channel); | ||
381 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
382 | u32 stage_id, u32 channel); | ||
383 | |||
384 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | 380 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, |
385 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); | 381 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); |
386 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, | 382 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, |
387 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); | 383 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); |
388 | 384 | ||
389 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
390 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
391 | enum sst_hsw_volume_curve curve); | ||
392 | |||
393 | /* Global Mixer Controls - */ | 385 | /* Global Mixer Controls - */ |
394 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
395 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
396 | |||
397 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | 386 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, |
398 | u32 volume); | 387 | u32 volume); |
399 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | 388 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, |
400 | u32 *volume); | 389 | u32 *volume); |
401 | 390 | ||
402 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
403 | u64 curve_duration, enum sst_hsw_volume_curve curve); | ||
404 | |||
405 | /* Stream API */ | 391 | /* Stream API */ |
406 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | 392 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, |
407 | u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), | 393 | u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), |
@@ -440,18 +426,14 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | |||
440 | struct sst_hsw_stream *stream, u32 offset, u32 size); | 426 | struct sst_hsw_stream *stream, u32 offset, u32 size); |
441 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | 427 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, |
442 | struct sst_hsw_stream *stream, u32 offset, u32 size); | 428 | struct sst_hsw_stream *stream, u32 offset, u32 size); |
443 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | 429 | snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw, |
444 | struct sst_hsw_stream *stream); | ||
445 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | ||
446 | struct sst_hsw_stream *stream); | ||
447 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | ||
448 | struct sst_hsw_stream *stream); | 430 | struct sst_hsw_stream *stream); |
449 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | 431 | void sst_hsw_stream_set_old_position(struct sst_hsw *hsw, |
432 | struct sst_hsw_stream *stream, snd_pcm_uframes_t val); | ||
433 | bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw, | ||
450 | struct sst_hsw_stream *stream); | 434 | struct sst_hsw_stream *stream); |
451 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | 435 | void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, |
452 | struct sst_hsw_stream *stream, u32 channel); | 436 | struct sst_hsw_stream *stream, bool val); |
453 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | ||
454 | struct sst_hsw_stream *stream, u32 channel); | ||
455 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw); | 437 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw); |
456 | 438 | ||
457 | /* Stream ALSA trigger operations */ | 439 | /* Stream ALSA trigger operations */ |
@@ -466,8 +448,6 @@ int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw, | |||
466 | struct sst_hsw_stream *stream, u32 *position); | 448 | struct sst_hsw_stream *stream, u32 *position); |
467 | int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, | 449 | int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, |
468 | struct sst_hsw_stream *stream, u32 *position); | 450 | struct sst_hsw_stream *stream, u32 *position); |
469 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
470 | struct sst_hsw_stream *stream, u32 stage_id, u32 position); | ||
471 | u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, | 451 | u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, |
472 | struct sst_hsw_stream *stream); | 452 | struct sst_hsw_stream *stream); |
473 | u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, | 453 | u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, |
@@ -481,8 +461,6 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, | |||
481 | /* DX Config */ | 461 | /* DX Config */ |
482 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, | 462 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, |
483 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); | 463 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); |
484 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | ||
485 | u32 *offset, u32 *size, u32 *source); | ||
486 | 464 | ||
487 | /* init */ | 465 | /* init */ |
488 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | 466 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 619525200705..d6fa9d5514e1 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -36,6 +36,11 @@ | |||
36 | #define HSW_PCM_COUNT 6 | 36 | #define HSW_PCM_COUNT 6 |
37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ | 37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ |
38 | 38 | ||
39 | #define SST_OLD_POSITION(d, r, o) ((d) + \ | ||
40 | frames_to_bytes(r, o)) | ||
41 | #define SST_SAMPLES(r, x) (bytes_to_samples(r, \ | ||
42 | frames_to_bytes(r, (x)))) | ||
43 | |||
39 | /* simple volume table */ | 44 | /* simple volume table */ |
40 | static const u32 volume_map[] = { | 45 | static const u32 volume_map[] = { |
41 | HSW_VOLUME_MAX >> 30, | 46 | HSW_VOLUME_MAX >> 30, |
@@ -78,7 +83,6 @@ static const u32 volume_map[] = { | |||
78 | #define HSW_PCM_DAI_ID_OFFLOAD0 1 | 83 | #define HSW_PCM_DAI_ID_OFFLOAD0 1 |
79 | #define HSW_PCM_DAI_ID_OFFLOAD1 2 | 84 | #define HSW_PCM_DAI_ID_OFFLOAD1 2 |
80 | #define HSW_PCM_DAI_ID_LOOPBACK 3 | 85 | #define HSW_PCM_DAI_ID_LOOPBACK 3 |
81 | #define HSW_PCM_DAI_ID_CAPTURE 4 | ||
82 | 86 | ||
83 | 87 | ||
84 | static const struct snd_pcm_hardware hsw_pcm_hardware = { | 88 | static const struct snd_pcm_hardware hsw_pcm_hardware = { |
@@ -99,6 +103,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { | |||
99 | 103 | ||
100 | struct hsw_pcm_module_map { | 104 | struct hsw_pcm_module_map { |
101 | int dai_id; | 105 | int dai_id; |
106 | int stream; | ||
102 | enum sst_hsw_module_id mod_id; | 107 | enum sst_hsw_module_id mod_id; |
103 | }; | 108 | }; |
104 | 109 | ||
@@ -119,8 +124,9 @@ struct hsw_pcm_data { | |||
119 | }; | 124 | }; |
120 | 125 | ||
121 | enum hsw_pm_state { | 126 | enum hsw_pm_state { |
122 | HSW_PM_STATE_D3 = 0, | 127 | HSW_PM_STATE_D0 = 0, |
123 | HSW_PM_STATE_D0 = 1, | 128 | HSW_PM_STATE_RTD3 = 1, |
129 | HSW_PM_STATE_D3 = 2, | ||
124 | }; | 130 | }; |
125 | 131 | ||
126 | /* private data for the driver */ | 132 | /* private data for the driver */ |
@@ -135,7 +141,17 @@ struct hsw_priv_data { | |||
135 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; | 141 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
136 | 142 | ||
137 | /* DAI data */ | 143 | /* DAI data */ |
138 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; | 144 | struct hsw_pcm_data pcm[HSW_PCM_COUNT][2]; |
145 | }; | ||
146 | |||
147 | |||
148 | /* static mappings between PCMs and modules - may be dynamic in future */ | ||
149 | static struct hsw_pcm_module_map mod_map[] = { | ||
150 | {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, | ||
151 | {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, | ||
152 | {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, | ||
153 | {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, | ||
154 | {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, | ||
139 | }; | 155 | }; |
140 | 156 | ||
141 | static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); | 157 | static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); |
@@ -168,9 +184,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
168 | (struct soc_mixer_control *)kcontrol->private_value; | 184 | (struct soc_mixer_control *)kcontrol->private_value; |
169 | struct hsw_priv_data *pdata = | 185 | struct hsw_priv_data *pdata = |
170 | snd_soc_platform_get_drvdata(platform); | 186 | snd_soc_platform_get_drvdata(platform); |
171 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 187 | struct hsw_pcm_data *pcm_data; |
172 | struct sst_hsw *hsw = pdata->hsw; | 188 | struct sst_hsw *hsw = pdata->hsw; |
173 | u32 volume; | 189 | u32 volume; |
190 | int dai, stream; | ||
191 | |||
192 | dai = mod_map[mc->reg].dai_id; | ||
193 | stream = mod_map[mc->reg].stream; | ||
194 | pcm_data = &pdata->pcm[dai][stream]; | ||
174 | 195 | ||
175 | mutex_lock(&pcm_data->mutex); | 196 | mutex_lock(&pcm_data->mutex); |
176 | pm_runtime_get_sync(pdata->dev); | 197 | pm_runtime_get_sync(pdata->dev); |
@@ -212,9 +233,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
212 | (struct soc_mixer_control *)kcontrol->private_value; | 233 | (struct soc_mixer_control *)kcontrol->private_value; |
213 | struct hsw_priv_data *pdata = | 234 | struct hsw_priv_data *pdata = |
214 | snd_soc_platform_get_drvdata(platform); | 235 | snd_soc_platform_get_drvdata(platform); |
215 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 236 | struct hsw_pcm_data *pcm_data; |
216 | struct sst_hsw *hsw = pdata->hsw; | 237 | struct sst_hsw *hsw = pdata->hsw; |
217 | u32 volume; | 238 | u32 volume; |
239 | int dai, stream; | ||
240 | |||
241 | dai = mod_map[mc->reg].dai_id; | ||
242 | stream = mod_map[mc->reg].stream; | ||
243 | pcm_data = &pdata->pcm[dai][stream]; | ||
218 | 244 | ||
219 | mutex_lock(&pcm_data->mutex); | 245 | mutex_lock(&pcm_data->mutex); |
220 | pm_runtime_get_sync(pdata->dev); | 246 | pm_runtime_get_sync(pdata->dev); |
@@ -309,7 +335,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { | |||
309 | ARRAY_SIZE(volume_map) - 1, 0, | 335 | ARRAY_SIZE(volume_map) - 1, 0, |
310 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 336 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
311 | /* Mic Capture volume */ | 337 | /* Mic Capture volume */ |
312 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8, | 338 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, |
313 | ARRAY_SIZE(volume_map) - 1, 0, | 339 | ARRAY_SIZE(volume_map) - 1, 0, |
314 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 340 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
315 | }; | 341 | }; |
@@ -353,7 +379,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
353 | struct snd_pcm_runtime *runtime = substream->runtime; | 379 | struct snd_pcm_runtime *runtime = substream->runtime; |
354 | struct hsw_priv_data *pdata = | 380 | struct hsw_priv_data *pdata = |
355 | snd_soc_platform_get_drvdata(rtd->platform); | 381 | snd_soc_platform_get_drvdata(rtd->platform); |
356 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | 382 | struct hsw_pcm_data *pcm_data; |
357 | struct sst_hsw *hsw = pdata->hsw; | 383 | struct sst_hsw *hsw = pdata->hsw; |
358 | struct sst_module *module_data; | 384 | struct sst_module *module_data; |
359 | struct sst_dsp *dsp; | 385 | struct sst_dsp *dsp; |
@@ -362,7 +388,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
362 | enum sst_hsw_stream_path_id path_id; | 388 | enum sst_hsw_stream_path_id path_id; |
363 | u32 rate, bits, map, pages, module_id; | 389 | u32 rate, bits, map, pages, module_id; |
364 | u8 channels; | 390 | u8 channels; |
365 | int ret; | 391 | int ret, dai; |
392 | |||
393 | dai = mod_map[rtd->cpu_dai->id].dai_id; | ||
394 | pcm_data = &pdata->pcm[dai][substream->stream]; | ||
366 | 395 | ||
367 | /* check if we are being called a subsequent time */ | 396 | /* check if we are being called a subsequent time */ |
368 | if (pcm_data->allocated) { | 397 | if (pcm_data->allocated) { |
@@ -552,20 +581,35 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
552 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 581 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
553 | struct hsw_priv_data *pdata = | 582 | struct hsw_priv_data *pdata = |
554 | snd_soc_platform_get_drvdata(rtd->platform); | 583 | snd_soc_platform_get_drvdata(rtd->platform); |
555 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | 584 | struct hsw_pcm_data *pcm_data; |
585 | struct sst_hsw_stream *sst_stream; | ||
556 | struct sst_hsw *hsw = pdata->hsw; | 586 | struct sst_hsw *hsw = pdata->hsw; |
587 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
588 | snd_pcm_uframes_t pos; | ||
589 | int dai; | ||
590 | |||
591 | dai = mod_map[rtd->cpu_dai->id].dai_id; | ||
592 | pcm_data = &pdata->pcm[dai][substream->stream]; | ||
593 | sst_stream = pcm_data->stream; | ||
557 | 594 | ||
558 | switch (cmd) { | 595 | switch (cmd) { |
559 | case SNDRV_PCM_TRIGGER_START: | 596 | case SNDRV_PCM_TRIGGER_START: |
560 | case SNDRV_PCM_TRIGGER_RESUME: | 597 | case SNDRV_PCM_TRIGGER_RESUME: |
561 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 598 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
599 | sst_hsw_stream_set_silence_start(hsw, sst_stream, false); | ||
562 | sst_hsw_stream_resume(hsw, pcm_data->stream, 0); | 600 | sst_hsw_stream_resume(hsw, pcm_data->stream, 0); |
563 | break; | 601 | break; |
564 | case SNDRV_PCM_TRIGGER_STOP: | 602 | case SNDRV_PCM_TRIGGER_STOP: |
565 | case SNDRV_PCM_TRIGGER_SUSPEND: | 603 | case SNDRV_PCM_TRIGGER_SUSPEND: |
566 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 604 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
605 | sst_hsw_stream_set_silence_start(hsw, sst_stream, false); | ||
567 | sst_hsw_stream_pause(hsw, pcm_data->stream, 0); | 606 | sst_hsw_stream_pause(hsw, pcm_data->stream, 0); |
568 | break; | 607 | break; |
608 | case SNDRV_PCM_TRIGGER_DRAIN: | ||
609 | pos = runtime->control->appl_ptr % runtime->buffer_size; | ||
610 | sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos); | ||
611 | sst_hsw_stream_set_silence_start(hsw, sst_stream, true); | ||
612 | break; | ||
569 | default: | 613 | default: |
570 | break; | 614 | break; |
571 | } | 615 | } |
@@ -579,13 +623,62 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) | |||
579 | struct snd_pcm_substream *substream = pcm_data->substream; | 623 | struct snd_pcm_substream *substream = pcm_data->substream; |
580 | struct snd_pcm_runtime *runtime = substream->runtime; | 624 | struct snd_pcm_runtime *runtime = substream->runtime; |
581 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 625 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
626 | struct hsw_priv_data *pdata = | ||
627 | snd_soc_platform_get_drvdata(rtd->platform); | ||
628 | struct sst_hsw *hsw = pdata->hsw; | ||
582 | u32 pos; | 629 | u32 pos; |
630 | snd_pcm_uframes_t position = bytes_to_frames(runtime, | ||
631 | sst_hsw_get_dsp_position(hsw, pcm_data->stream)); | ||
632 | unsigned char *dma_area = runtime->dma_area; | ||
633 | snd_pcm_uframes_t dma_frames = | ||
634 | bytes_to_frames(runtime, runtime->dma_bytes); | ||
635 | snd_pcm_uframes_t old_position; | ||
636 | ssize_t samples; | ||
583 | 637 | ||
584 | pos = frames_to_bytes(runtime, | 638 | pos = frames_to_bytes(runtime, |
585 | (runtime->control->appl_ptr % runtime->buffer_size)); | 639 | (runtime->control->appl_ptr % runtime->buffer_size)); |
586 | 640 | ||
587 | dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | 641 | dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); |
588 | 642 | ||
643 | /* SST fw don't know where to stop dma | ||
644 | * So, SST driver need to clean the data which has been consumed | ||
645 | */ | ||
646 | if (dma_area == NULL || dma_frames <= 0 | ||
647 | || (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
648 | || !sst_hsw_stream_get_silence_start(hsw, stream)) { | ||
649 | snd_pcm_period_elapsed(substream); | ||
650 | return pos; | ||
651 | } | ||
652 | |||
653 | old_position = sst_hsw_stream_get_old_position(hsw, stream); | ||
654 | if (position > old_position) { | ||
655 | if (position < dma_frames) { | ||
656 | samples = SST_SAMPLES(runtime, position - old_position); | ||
657 | snd_pcm_format_set_silence(runtime->format, | ||
658 | SST_OLD_POSITION(dma_area, | ||
659 | runtime, old_position), | ||
660 | samples); | ||
661 | } else | ||
662 | dev_err(rtd->dev, "PCM: position is wrong\n"); | ||
663 | } else { | ||
664 | if (old_position < dma_frames) { | ||
665 | samples = SST_SAMPLES(runtime, | ||
666 | dma_frames - old_position); | ||
667 | snd_pcm_format_set_silence(runtime->format, | ||
668 | SST_OLD_POSITION(dma_area, | ||
669 | runtime, old_position), | ||
670 | samples); | ||
671 | } else | ||
672 | dev_err(rtd->dev, "PCM: dma_bytes is wrong\n"); | ||
673 | if (position < dma_frames) { | ||
674 | samples = SST_SAMPLES(runtime, position); | ||
675 | snd_pcm_format_set_silence(runtime->format, | ||
676 | dma_area, samples); | ||
677 | } else | ||
678 | dev_err(rtd->dev, "PCM: position is wrong\n"); | ||
679 | } | ||
680 | sst_hsw_stream_set_old_position(hsw, stream, position); | ||
681 | |||
589 | /* let alsa know we have play a period */ | 682 | /* let alsa know we have play a period */ |
590 | snd_pcm_period_elapsed(substream); | 683 | snd_pcm_period_elapsed(substream); |
591 | return pos; | 684 | return pos; |
@@ -597,11 +690,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | |||
597 | struct snd_pcm_runtime *runtime = substream->runtime; | 690 | struct snd_pcm_runtime *runtime = substream->runtime; |
598 | struct hsw_priv_data *pdata = | 691 | struct hsw_priv_data *pdata = |
599 | snd_soc_platform_get_drvdata(rtd->platform); | 692 | snd_soc_platform_get_drvdata(rtd->platform); |
600 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | 693 | struct hsw_pcm_data *pcm_data; |
601 | struct sst_hsw *hsw = pdata->hsw; | 694 | struct sst_hsw *hsw = pdata->hsw; |
602 | snd_pcm_uframes_t offset; | 695 | snd_pcm_uframes_t offset; |
603 | uint64_t ppos; | 696 | uint64_t ppos; |
604 | u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); | 697 | u32 position; |
698 | int dai; | ||
699 | |||
700 | dai = mod_map[rtd->cpu_dai->id].dai_id; | ||
701 | pcm_data = &pdata->pcm[dai][substream->stream]; | ||
702 | position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); | ||
605 | 703 | ||
606 | offset = bytes_to_frames(runtime, position); | 704 | offset = bytes_to_frames(runtime, position); |
607 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); | 705 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); |
@@ -618,8 +716,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
618 | snd_soc_platform_get_drvdata(rtd->platform); | 716 | snd_soc_platform_get_drvdata(rtd->platform); |
619 | struct hsw_pcm_data *pcm_data; | 717 | struct hsw_pcm_data *pcm_data; |
620 | struct sst_hsw *hsw = pdata->hsw; | 718 | struct sst_hsw *hsw = pdata->hsw; |
719 | int dai; | ||
621 | 720 | ||
622 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | 721 | dai = mod_map[rtd->cpu_dai->id].dai_id; |
722 | pcm_data = &pdata->pcm[dai][substream->stream]; | ||
623 | 723 | ||
624 | mutex_lock(&pcm_data->mutex); | 724 | mutex_lock(&pcm_data->mutex); |
625 | pm_runtime_get_sync(pdata->dev); | 725 | pm_runtime_get_sync(pdata->dev); |
@@ -648,9 +748,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) | |||
648 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 748 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
649 | struct hsw_priv_data *pdata = | 749 | struct hsw_priv_data *pdata = |
650 | snd_soc_platform_get_drvdata(rtd->platform); | 750 | snd_soc_platform_get_drvdata(rtd->platform); |
651 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | 751 | struct hsw_pcm_data *pcm_data; |
652 | struct sst_hsw *hsw = pdata->hsw; | 752 | struct sst_hsw *hsw = pdata->hsw; |
653 | int ret; | 753 | int ret, dai; |
754 | |||
755 | dai = mod_map[rtd->cpu_dai->id].dai_id; | ||
756 | pcm_data = &pdata->pcm[dai][substream->stream]; | ||
654 | 757 | ||
655 | mutex_lock(&pcm_data->mutex); | 758 | mutex_lock(&pcm_data->mutex); |
656 | ret = sst_hsw_stream_reset(hsw, pcm_data->stream); | 759 | ret = sst_hsw_stream_reset(hsw, pcm_data->stream); |
@@ -685,15 +788,6 @@ static struct snd_pcm_ops hsw_pcm_ops = { | |||
685 | .page = snd_pcm_sgbuf_ops_page, | 788 | .page = snd_pcm_sgbuf_ops_page, |
686 | }; | 789 | }; |
687 | 790 | ||
688 | /* static mappings between PCMs and modules - may be dynamic in future */ | ||
689 | static struct hsw_pcm_module_map mod_map[] = { | ||
690 | {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM}, | ||
691 | {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM}, | ||
692 | {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM}, | ||
693 | {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE}, | ||
694 | {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE}, | ||
695 | }; | ||
696 | |||
697 | static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | 791 | static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) |
698 | { | 792 | { |
699 | struct sst_hsw *hsw = pdata->hsw; | 793 | struct sst_hsw *hsw = pdata->hsw; |
@@ -701,7 +795,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | |||
701 | int i; | 795 | int i; |
702 | 796 | ||
703 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | 797 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
704 | pcm_data = &pdata->pcm[i]; | 798 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
705 | 799 | ||
706 | /* create new runtime module, use same offset if recreated */ | 800 | /* create new runtime module, use same offset if recreated */ |
707 | pcm_data->runtime = sst_hsw_runtime_module_create(hsw, | 801 | pcm_data->runtime = sst_hsw_runtime_module_create(hsw, |
@@ -716,7 +810,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | |||
716 | 810 | ||
717 | err: | 811 | err: |
718 | for (--i; i >= 0; i--) { | 812 | for (--i; i >= 0; i--) { |
719 | pcm_data = &pdata->pcm[i]; | 813 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
720 | sst_hsw_runtime_module_free(pcm_data->runtime); | 814 | sst_hsw_runtime_module_free(pcm_data->runtime); |
721 | } | 815 | } |
722 | 816 | ||
@@ -729,17 +823,12 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | |||
729 | int i; | 823 | int i; |
730 | 824 | ||
731 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | 825 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
732 | pcm_data = &pdata->pcm[i]; | 826 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
733 | 827 | ||
734 | sst_hsw_runtime_module_free(pcm_data->runtime); | 828 | sst_hsw_runtime_module_free(pcm_data->runtime); |
735 | } | 829 | } |
736 | } | 830 | } |
737 | 831 | ||
738 | static void hsw_pcm_free(struct snd_pcm *pcm) | ||
739 | { | ||
740 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
741 | } | ||
742 | |||
743 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | 832 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) |
744 | { | 833 | { |
745 | struct snd_pcm *pcm = rtd->pcm; | 834 | struct snd_pcm *pcm = rtd->pcm; |
@@ -762,7 +851,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
762 | return ret; | 851 | return ret; |
763 | } | 852 | } |
764 | } | 853 | } |
765 | priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm; | 854 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) |
855 | priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm; | ||
856 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) | ||
857 | priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm; | ||
766 | 858 | ||
767 | return ret; | 859 | return ret; |
768 | } | 860 | } |
@@ -871,10 +963,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
871 | /* allocate DSP buffer page tables */ | 963 | /* allocate DSP buffer page tables */ |
872 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 964 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
873 | 965 | ||
874 | mutex_init(&priv_data->pcm[i].mutex); | ||
875 | |||
876 | /* playback */ | 966 | /* playback */ |
877 | if (hsw_dais[i].playback.channels_min) { | 967 | if (hsw_dais[i].playback.channels_min) { |
968 | mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex); | ||
878 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, | 969 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
879 | PAGE_SIZE, &priv_data->dmab[i][0]); | 970 | PAGE_SIZE, &priv_data->dmab[i][0]); |
880 | if (ret < 0) | 971 | if (ret < 0) |
@@ -883,6 +974,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
883 | 974 | ||
884 | /* capture */ | 975 | /* capture */ |
885 | if (hsw_dais[i].capture.channels_min) { | 976 | if (hsw_dais[i].capture.channels_min) { |
977 | mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex); | ||
886 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, | 978 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, |
887 | PAGE_SIZE, &priv_data->dmab[i][1]); | 979 | PAGE_SIZE, &priv_data->dmab[i][1]); |
888 | if (ret < 0) | 980 | if (ret < 0) |
@@ -936,7 +1028,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = { | |||
936 | .remove = hsw_pcm_remove, | 1028 | .remove = hsw_pcm_remove, |
937 | .ops = &hsw_pcm_ops, | 1029 | .ops = &hsw_pcm_ops, |
938 | .pcm_new = hsw_pcm_new, | 1030 | .pcm_new = hsw_pcm_new, |
939 | .pcm_free = hsw_pcm_free, | ||
940 | }; | 1031 | }; |
941 | 1032 | ||
942 | static const struct snd_soc_component_driver hsw_dai_component = { | 1033 | static const struct snd_soc_component_driver hsw_dai_component = { |
@@ -1010,12 +1101,12 @@ static int hsw_pcm_runtime_suspend(struct device *dev) | |||
1010 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | 1101 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); |
1011 | struct sst_hsw *hsw = pdata->hsw; | 1102 | struct sst_hsw *hsw = pdata->hsw; |
1012 | 1103 | ||
1013 | if (pdata->pm_state == HSW_PM_STATE_D3) | 1104 | if (pdata->pm_state >= HSW_PM_STATE_RTD3) |
1014 | return 0; | 1105 | return 0; |
1015 | 1106 | ||
1016 | sst_hsw_dsp_runtime_suspend(hsw); | 1107 | sst_hsw_dsp_runtime_suspend(hsw); |
1017 | sst_hsw_dsp_runtime_sleep(hsw); | 1108 | sst_hsw_dsp_runtime_sleep(hsw); |
1018 | pdata->pm_state = HSW_PM_STATE_D3; | 1109 | pdata->pm_state = HSW_PM_STATE_RTD3; |
1019 | 1110 | ||
1020 | return 0; | 1111 | return 0; |
1021 | } | 1112 | } |
@@ -1026,7 +1117,7 @@ static int hsw_pcm_runtime_resume(struct device *dev) | |||
1026 | struct sst_hsw *hsw = pdata->hsw; | 1117 | struct sst_hsw *hsw = pdata->hsw; |
1027 | int ret; | 1118 | int ret; |
1028 | 1119 | ||
1029 | if (pdata->pm_state == HSW_PM_STATE_D0) | 1120 | if (pdata->pm_state != HSW_PM_STATE_RTD3) |
1030 | return 0; | 1121 | return 0; |
1031 | 1122 | ||
1032 | ret = sst_hsw_dsp_load(hsw); | 1123 | ret = sst_hsw_dsp_load(hsw); |
@@ -1066,7 +1157,7 @@ static void hsw_pcm_complete(struct device *dev) | |||
1066 | struct hsw_pcm_data *pcm_data; | 1157 | struct hsw_pcm_data *pcm_data; |
1067 | int i, err; | 1158 | int i, err; |
1068 | 1159 | ||
1069 | if (pdata->pm_state == HSW_PM_STATE_D0) | 1160 | if (pdata->pm_state != HSW_PM_STATE_D3) |
1070 | return; | 1161 | return; |
1071 | 1162 | ||
1072 | err = sst_hsw_dsp_load(hsw); | 1163 | err = sst_hsw_dsp_load(hsw); |
@@ -1081,8 +1172,8 @@ static void hsw_pcm_complete(struct device *dev) | |||
1081 | return; | 1172 | return; |
1082 | } | 1173 | } |
1083 | 1174 | ||
1084 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | 1175 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
1085 | pcm_data = &pdata->pcm[i]; | 1176 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
1086 | 1177 | ||
1087 | if (!pcm_data->substream) | 1178 | if (!pcm_data->substream) |
1088 | continue; | 1179 | continue; |
@@ -1114,41 +1205,42 @@ static int hsw_pcm_prepare(struct device *dev) | |||
1114 | 1205 | ||
1115 | if (pdata->pm_state == HSW_PM_STATE_D3) | 1206 | if (pdata->pm_state == HSW_PM_STATE_D3) |
1116 | return 0; | 1207 | return 0; |
1117 | /* suspend all active streams */ | 1208 | else if (pdata->pm_state == HSW_PM_STATE_D0) { |
1118 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | 1209 | /* suspend all active streams */ |
1119 | pcm_data = &pdata->pcm[i]; | 1210 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
1211 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; | ||
1212 | |||
1213 | if (!pcm_data->substream) | ||
1214 | continue; | ||
1215 | dev_dbg(dev, "suspending pcm %d\n", i); | ||
1216 | snd_pcm_suspend_all(pcm_data->hsw_pcm); | ||
1217 | |||
1218 | /* We need to wait until the DSP FW stops the streams */ | ||
1219 | msleep(2); | ||
1220 | } | ||
1120 | 1221 | ||
1121 | if (!pcm_data->substream) | 1222 | /* preserve persistent memory */ |
1122 | continue; | 1223 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
1123 | dev_dbg(dev, "suspending pcm %d\n", i); | 1224 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
1124 | snd_pcm_suspend_all(pcm_data->hsw_pcm); | 1225 | |
1226 | if (!pcm_data->substream) | ||
1227 | continue; | ||
1125 | 1228 | ||
1126 | /* We need to wait until the DSP FW stops the streams */ | 1229 | dev_dbg(dev, "saving context pcm %d\n", i); |
1127 | msleep(2); | 1230 | err = sst_module_runtime_save(pcm_data->runtime, |
1231 | &pcm_data->context); | ||
1232 | if (err < 0) | ||
1233 | dev_err(dev, "failed to save context for PCM %d\n", i); | ||
1234 | } | ||
1235 | /* enter D3 state and stall */ | ||
1236 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1237 | /* put the DSP to sleep */ | ||
1238 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1128 | } | 1239 | } |
1129 | 1240 | ||
1130 | snd_soc_suspend(pdata->soc_card->dev); | 1241 | snd_soc_suspend(pdata->soc_card->dev); |
1131 | snd_soc_poweroff(pdata->soc_card->dev); | 1242 | snd_soc_poweroff(pdata->soc_card->dev); |
1132 | 1243 | ||
1133 | /* enter D3 state and stall */ | ||
1134 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1135 | |||
1136 | /* preserve persistent memory */ | ||
1137 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1138 | pcm_data = &pdata->pcm[i]; | ||
1139 | |||
1140 | if (!pcm_data->substream) | ||
1141 | continue; | ||
1142 | |||
1143 | dev_dbg(dev, "saving context pcm %d\n", i); | ||
1144 | err = sst_module_runtime_save(pcm_data->runtime, | ||
1145 | &pcm_data->context); | ||
1146 | if (err < 0) | ||
1147 | dev_err(dev, "failed to save context for PCM %d\n", i); | ||
1148 | } | ||
1149 | |||
1150 | /* put the DSP to sleep */ | ||
1151 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1152 | pdata->pm_state = HSW_PM_STATE_D3; | 1244 | pdata->pm_state = HSW_PM_STATE_D3; |
1153 | 1245 | ||
1154 | return 0; | 1246 | return 0; |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index a1a8d9d91539..7523cbef8780 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = { | |||
643 | .pointer = sst_platform_pcm_pointer, | 643 | .pointer = sst_platform_pcm_pointer, |
644 | }; | 644 | }; |
645 | 645 | ||
646 | static void sst_pcm_free(struct snd_pcm *pcm) | ||
647 | { | ||
648 | dev_dbg(pcm->dev, "sst_pcm_free called\n"); | ||
649 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
650 | } | ||
651 | |||
652 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | 646 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) |
653 | { | 647 | { |
654 | struct snd_soc_dai *dai = rtd->cpu_dai; | 648 | struct snd_soc_dai *dai = rtd->cpu_dai; |
@@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = { | |||
679 | .ops = &sst_platform_ops, | 673 | .ops = &sst_platform_ops, |
680 | .compr_ops = &sst_platform_compr_ops, | 674 | .compr_ops = &sst_platform_compr_ops, |
681 | .pcm_new = sst_pcm_new, | 675 | .pcm_new = sst_pcm_new, |
682 | .pcm_free = sst_pcm_free, | ||
683 | }; | 676 | }; |
684 | 677 | ||
685 | static const struct snd_soc_component_driver sst_component = { | 678 | static const struct snd_soc_component_driver sst_component = { |
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 7f4bbfcbc6f5..562bc483d6b7 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h | |||
@@ -58,6 +58,7 @@ enum sst_algo_ops { | |||
58 | #define SST_BLOCK_TIMEOUT 1000 | 58 | #define SST_BLOCK_TIMEOUT 1000 |
59 | 59 | ||
60 | #define FW_SIGNATURE_SIZE 4 | 60 | #define FW_SIGNATURE_SIZE 4 |
61 | #define FW_NAME_SIZE 32 | ||
61 | 62 | ||
62 | /* stream states */ | 63 | /* stream states */ |
63 | enum sst_stream_states { | 64 | enum sst_stream_states { |
@@ -426,7 +427,7 @@ struct intel_sst_drv { | |||
426 | * Holder for firmware name. Due to async call it needs to be | 427 | * Holder for firmware name. Due to async call it needs to be |
427 | * persistent till worker thread gets called | 428 | * persistent till worker thread gets called |
428 | */ | 429 | */ |
429 | char firmware_name[20]; | 430 | char firmware_name[FW_NAME_SIZE]; |
430 | }; | 431 | }; |
431 | 432 | ||
432 | /* misc definitions */ | 433 | /* misc definitions */ |
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index b3360139c41a..b782dfdcdbba 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c | |||
@@ -47,7 +47,7 @@ struct sst_machines { | |||
47 | char board[32]; | 47 | char board[32]; |
48 | char machine[32]; | 48 | char machine[32]; |
49 | void (*machine_quirk)(void); | 49 | void (*machine_quirk)(void); |
50 | char firmware[32]; | 50 | char firmware[FW_NAME_SIZE]; |
51 | struct sst_platform_info *pdata; | 51 | struct sst_platform_info *pdata; |
52 | 52 | ||
53 | }; | 53 | }; |
@@ -245,7 +245,7 @@ static struct sst_machines *sst_acpi_find_machine( | |||
245 | return NULL; | 245 | return NULL; |
246 | } | 246 | } |
247 | 247 | ||
248 | int sst_acpi_probe(struct platform_device *pdev) | 248 | static int sst_acpi_probe(struct platform_device *pdev) |
249 | { | 249 | { |
250 | struct device *dev = &pdev->dev; | 250 | struct device *dev = &pdev->dev; |
251 | int ret = 0; | 251 | int ret = 0; |
@@ -332,7 +332,7 @@ do_sst_cleanup: | |||
332 | * This function is called by OS when a device is unloaded | 332 | * This function is called by OS when a device is unloaded |
333 | * This frees the interrupt etc | 333 | * This frees the interrupt etc |
334 | */ | 334 | */ |
335 | int sst_acpi_remove(struct platform_device *pdev) | 335 | static int sst_acpi_remove(struct platform_device *pdev) |
336 | { | 336 | { |
337 | struct intel_sst_drv *ctx; | 337 | struct intel_sst_drv *ctx; |
338 | 338 | ||
@@ -352,6 +352,8 @@ static struct sst_machines sst_acpi_bytcr[] = { | |||
352 | static struct sst_machines sst_acpi_chv[] = { | 352 | static struct sst_machines sst_acpi_chv[] = { |
353 | {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", | 353 | {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", |
354 | &chv_platform_data }, | 354 | &chv_platform_data }, |
355 | {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", | ||
356 | &chv_platform_data }, | ||
355 | {}, | 357 | {}, |
356 | }; | 358 | }; |
357 | 359 | ||
@@ -366,7 +368,6 @@ MODULE_DEVICE_TABLE(acpi, sst_acpi_ids); | |||
366 | static struct platform_driver sst_acpi_driver = { | 368 | static struct platform_driver sst_acpi_driver = { |
367 | .driver = { | 369 | .driver = { |
368 | .name = "intel_sst_acpi", | 370 | .name = "intel_sst_acpi", |
369 | .owner = THIS_MODULE, | ||
370 | .acpi_match_table = ACPI_PTR(sst_acpi_ids), | 371 | .acpi_match_table = ACPI_PTR(sst_acpi_ids), |
371 | .pm = &intel_sst_pm, | 372 | .pm = &intel_sst_pm, |
372 | }, | 373 | }, |
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index b580f96e25e5..7888cd707853 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c | |||
@@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context) | |||
324 | 324 | ||
325 | if (ctx->sst_state != SST_RESET || | 325 | if (ctx->sst_state != SST_RESET || |
326 | ctx->fw_in_mem != NULL) { | 326 | ctx->fw_in_mem != NULL) { |
327 | if (fw != NULL) | 327 | release_firmware(fw); |
328 | release_firmware(fw); | ||
329 | mutex_unlock(&ctx->sst_lock); | 328 | mutex_unlock(&ctx->sst_lock); |
330 | return; | 329 | return; |
331 | } | 330 | } |