diff options
24 files changed, 555 insertions, 140 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt index 8dbce0e18dda..1447dec28125 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt | |||
@@ -13,6 +13,11 @@ Required properties: | |||
13 | - reg: The i2c address. Value depends on the state of ADDR0 | 13 | - reg: The i2c address. Value depends on the state of ADDR0 |
14 | and ADDR1, as wired in hardware. | 14 | and ADDR1, as wired in hardware. |
15 | 15 | ||
16 | Optional properties: | ||
17 | - clock-names: If provided must be "mclk". | ||
18 | - clocks: phandle + clock-specifiers for the clock that provides | ||
19 | the audio master clock for the device. | ||
20 | |||
16 | Examples: | 21 | Examples: |
17 | #include <dt-bindings/sound/adau17x1.h> | 22 | #include <dt-bindings/sound/adau17x1.h> |
18 | 23 | ||
@@ -20,5 +25,8 @@ Examples: | |||
20 | adau1361@38 { | 25 | adau1361@38 { |
21 | compatible = "adi,adau1761"; | 26 | compatible = "adi,adau1761"; |
22 | reg = <0x38>; | 27 | reg = <0x38>; |
28 | |||
29 | clock-names = "mclk"; | ||
30 | clocks = <&audio_clock>; | ||
23 | }; | 31 | }; |
24 | }; | 32 | }; |
diff --git a/Documentation/devicetree/bindings/sound/adi,adau7002.txt b/Documentation/devicetree/bindings/sound/adi,adau7002.txt new file mode 100644 index 000000000000..f144ee1abf85 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau7002.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: Must be "adi,adau7002" | ||
6 | |||
7 | Optional properties: | ||
8 | |||
9 | - IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD | ||
10 | supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt | ||
11 | |||
12 | If this property is not present it is assumed that the supply pin is | ||
13 | hardwired to always on. | ||
14 | |||
15 | Example: | ||
16 | adau7002: pdm-to-i2s { | ||
17 | compatible = "adi,adau7002"; | ||
18 | IOVDD-supply = <&supply>; | ||
19 | }; | ||
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index d55a42297d49..58ab4c0fe761 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define _WM_ARIZONA_CORE_H | 14 | #define _WM_ARIZONA_CORE_H |
15 | 15 | ||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/notifier.h> | ||
17 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
18 | #include <linux/regulator/consumer.h> | 19 | #include <linux/regulator/consumer.h> |
19 | #include <linux/mfd/arizona/pdata.h> | 20 | #include <linux/mfd/arizona/pdata.h> |
@@ -148,8 +149,17 @@ struct arizona { | |||
148 | uint16_t dac_comp_coeff; | 149 | uint16_t dac_comp_coeff; |
149 | uint8_t dac_comp_enabled; | 150 | uint8_t dac_comp_enabled; |
150 | struct mutex dac_comp_lock; | 151 | struct mutex dac_comp_lock; |
152 | |||
153 | struct blocking_notifier_head notifier; | ||
151 | }; | 154 | }; |
152 | 155 | ||
156 | static inline int arizona_call_notifiers(struct arizona *arizona, | ||
157 | unsigned long event, | ||
158 | void *data) | ||
159 | { | ||
160 | return blocking_notifier_call_chain(&arizona->notifier, event, data); | ||
161 | } | ||
162 | |||
153 | int arizona_clk32k_enable(struct arizona *arizona); | 163 | int arizona_clk32k_enable(struct arizona *arizona); |
154 | int arizona_clk32k_disable(struct arizona *arizona); | 164 | int arizona_clk32k_disable(struct arizona *arizona); |
155 | 165 | ||
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index c0abcdc11470..cee8c00f3d3e 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h | |||
@@ -68,6 +68,7 @@ struct snd_compr_runtime { | |||
68 | * @ops: pointer to DSP callbacks | 68 | * @ops: pointer to DSP callbacks |
69 | * @runtime: pointer to runtime structure | 69 | * @runtime: pointer to runtime structure |
70 | * @device: device pointer | 70 | * @device: device pointer |
71 | * @error_work: delayed work used when closing the stream due to an error | ||
71 | * @direction: stream direction, playback/recording | 72 | * @direction: stream direction, playback/recording |
72 | * @metadata_set: metadata set flag, true when set | 73 | * @metadata_set: metadata set flag, true when set |
73 | * @next_track: has userspace signal next track transition, true when set | 74 | * @next_track: has userspace signal next track transition, true when set |
@@ -78,6 +79,7 @@ struct snd_compr_stream { | |||
78 | struct snd_compr_ops *ops; | 79 | struct snd_compr_ops *ops; |
79 | struct snd_compr_runtime *runtime; | 80 | struct snd_compr_runtime *runtime; |
80 | struct snd_compr *device; | 81 | struct snd_compr *device; |
82 | struct delayed_work error_work; | ||
81 | enum snd_compr_direction direction; | 83 | enum snd_compr_direction direction; |
82 | bool metadata_set; | 84 | bool metadata_set; |
83 | bool next_track; | 85 | bool next_track; |
@@ -187,4 +189,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) | |||
187 | wake_up(&stream->runtime->sleep); | 189 | wake_up(&stream->runtime->sleep); |
188 | } | 190 | } |
189 | 191 | ||
192 | int snd_compr_stop_error(struct snd_compr_stream *stream, | ||
193 | snd_pcm_state_t state); | ||
194 | |||
190 | #endif | 195 | #endif |
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 9b3334be9df2..2c498488af6c 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -67,6 +67,8 @@ struct snd_compr_file { | |||
67 | struct snd_compr_stream stream; | 67 | struct snd_compr_stream stream; |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static void error_delayed_work(struct work_struct *work); | ||
71 | |||
70 | /* | 72 | /* |
71 | * a note on stream states used: | 73 | * a note on stream states used: |
72 | * we use following states in the compressed core | 74 | * we use following states in the compressed core |
@@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
123 | snd_card_unref(compr->card); | 125 | snd_card_unref(compr->card); |
124 | return -ENOMEM; | 126 | return -ENOMEM; |
125 | } | 127 | } |
128 | |||
129 | INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work); | ||
130 | |||
126 | data->stream.ops = compr->ops; | 131 | data->stream.ops = compr->ops; |
127 | data->stream.direction = dirn; | 132 | data->stream.direction = dirn; |
128 | data->stream.private_data = compr->private_data; | 133 | data->stream.private_data = compr->private_data; |
@@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) | |||
153 | struct snd_compr_file *data = f->private_data; | 158 | struct snd_compr_file *data = f->private_data; |
154 | struct snd_compr_runtime *runtime = data->stream.runtime; | 159 | struct snd_compr_runtime *runtime = data->stream.runtime; |
155 | 160 | ||
161 | cancel_delayed_work_sync(&data->stream.error_work); | ||
162 | |||
156 | switch (runtime->state) { | 163 | switch (runtime->state) { |
157 | case SNDRV_PCM_STATE_RUNNING: | 164 | case SNDRV_PCM_STATE_RUNNING: |
158 | case SNDRV_PCM_STATE_DRAINING: | 165 | case SNDRV_PCM_STATE_DRAINING: |
@@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) | |||
237 | avail = snd_compr_calc_avail(stream, &ioctl_avail); | 244 | avail = snd_compr_calc_avail(stream, &ioctl_avail); |
238 | ioctl_avail.avail = avail; | 245 | ioctl_avail.avail = avail; |
239 | 246 | ||
247 | switch (stream->runtime->state) { | ||
248 | case SNDRV_PCM_STATE_OPEN: | ||
249 | return -EBADFD; | ||
250 | case SNDRV_PCM_STATE_XRUN: | ||
251 | return -EPIPE; | ||
252 | default: | ||
253 | break; | ||
254 | } | ||
255 | |||
240 | if (copy_to_user((__u64 __user *)arg, | 256 | if (copy_to_user((__u64 __user *)arg, |
241 | &ioctl_avail, sizeof(ioctl_avail))) | 257 | &ioctl_avail, sizeof(ioctl_avail))) |
242 | return -EFAULT; | 258 | return -EFAULT; |
@@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, | |||
346 | switch (stream->runtime->state) { | 362 | switch (stream->runtime->state) { |
347 | case SNDRV_PCM_STATE_OPEN: | 363 | case SNDRV_PCM_STATE_OPEN: |
348 | case SNDRV_PCM_STATE_PREPARED: | 364 | case SNDRV_PCM_STATE_PREPARED: |
349 | case SNDRV_PCM_STATE_XRUN: | ||
350 | case SNDRV_PCM_STATE_SUSPENDED: | 365 | case SNDRV_PCM_STATE_SUSPENDED: |
351 | case SNDRV_PCM_STATE_DISCONNECTED: | 366 | case SNDRV_PCM_STATE_DISCONNECTED: |
352 | retval = -EBADFD; | 367 | retval = -EBADFD; |
353 | goto out; | 368 | goto out; |
369 | case SNDRV_PCM_STATE_XRUN: | ||
370 | retval = -EPIPE; | ||
371 | goto out; | ||
354 | } | 372 | } |
355 | 373 | ||
356 | avail = snd_compr_get_avail(stream); | 374 | avail = snd_compr_get_avail(stream); |
@@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait) | |||
399 | stream = &data->stream; | 417 | stream = &data->stream; |
400 | 418 | ||
401 | mutex_lock(&stream->device->lock); | 419 | mutex_lock(&stream->device->lock); |
402 | if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { | 420 | |
421 | switch (stream->runtime->state) { | ||
422 | case SNDRV_PCM_STATE_OPEN: | ||
423 | case SNDRV_PCM_STATE_XRUN: | ||
403 | retval = snd_compr_get_poll(stream) | POLLERR; | 424 | retval = snd_compr_get_poll(stream) | POLLERR; |
404 | goto out; | 425 | goto out; |
426 | default: | ||
427 | break; | ||
405 | } | 428 | } |
429 | |||
406 | poll_wait(f, &stream->runtime->sleep, wait); | 430 | poll_wait(f, &stream->runtime->sleep, wait); |
407 | 431 | ||
408 | avail = snd_compr_get_avail(stream); | 432 | avail = snd_compr_get_avail(stream); |
@@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream) | |||
697 | return retval; | 721 | return retval; |
698 | } | 722 | } |
699 | 723 | ||
724 | static void error_delayed_work(struct work_struct *work) | ||
725 | { | ||
726 | struct snd_compr_stream *stream; | ||
727 | |||
728 | stream = container_of(work, struct snd_compr_stream, error_work.work); | ||
729 | |||
730 | mutex_lock(&stream->device->lock); | ||
731 | |||
732 | stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); | ||
733 | wake_up(&stream->runtime->sleep); | ||
734 | |||
735 | mutex_unlock(&stream->device->lock); | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * snd_compr_stop_error: Report a fatal error on a stream | ||
740 | * @stream: pointer to stream | ||
741 | * @state: state to transition the stream to | ||
742 | * | ||
743 | * Stop the stream and set its state. | ||
744 | * | ||
745 | * Should be called with compressed device lock held. | ||
746 | */ | ||
747 | int snd_compr_stop_error(struct snd_compr_stream *stream, | ||
748 | snd_pcm_state_t state) | ||
749 | { | ||
750 | if (stream->runtime->state == state) | ||
751 | return 0; | ||
752 | |||
753 | stream->runtime->state = state; | ||
754 | |||
755 | pr_debug("Changing state to: %d\n", state); | ||
756 | |||
757 | queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | EXPORT_SYMBOL_GPL(snd_compr_stop_error); | ||
762 | |||
700 | static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) | 763 | static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) |
701 | { | 764 | { |
702 | int ret; | 765 | int ret; |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f3fb98f0a995..a9faf3711064 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS | |||
32 | select SND_SOC_ADAU1977_SPI if SPI_MASTER | 32 | select SND_SOC_ADAU1977_SPI if SPI_MASTER |
33 | select SND_SOC_ADAU1977_I2C if I2C | 33 | select SND_SOC_ADAU1977_I2C if I2C |
34 | select SND_SOC_ADAU1701 if I2C | 34 | select SND_SOC_ADAU1701 if I2C |
35 | select SND_SOC_ADAU7002 | ||
35 | select SND_SOC_ADS117X | 36 | select SND_SOC_ADS117X |
36 | select SND_SOC_AK4104 if SPI_MASTER | 37 | select SND_SOC_AK4104 if SPI_MASTER |
37 | select SND_SOC_AK4535 if I2C | 38 | select SND_SOC_AK4535 if I2C |
@@ -269,8 +270,12 @@ config SND_SOC_AD1980 | |||
269 | config SND_SOC_AD73311 | 270 | config SND_SOC_AD73311 |
270 | tristate | 271 | tristate |
271 | 272 | ||
273 | config SND_SOC_ADAU_UTILS | ||
274 | tristate | ||
275 | |||
272 | config SND_SOC_ADAU1373 | 276 | config SND_SOC_ADAU1373 |
273 | tristate | 277 | tristate |
278 | select SND_SOC_ADAU_UTILS | ||
274 | 279 | ||
275 | config SND_SOC_ADAU1701 | 280 | config SND_SOC_ADAU1701 |
276 | tristate "Analog Devices ADAU1701 CODEC" | 281 | tristate "Analog Devices ADAU1701 CODEC" |
@@ -280,6 +285,7 @@ config SND_SOC_ADAU1701 | |||
280 | config SND_SOC_ADAU17X1 | 285 | config SND_SOC_ADAU17X1 |
281 | tristate | 286 | tristate |
282 | select SND_SOC_SIGMADSP_REGMAP | 287 | select SND_SOC_SIGMADSP_REGMAP |
288 | select SND_SOC_ADAU_UTILS | ||
283 | 289 | ||
284 | config SND_SOC_ADAU1761 | 290 | config SND_SOC_ADAU1761 |
285 | tristate | 291 | tristate |
@@ -322,6 +328,9 @@ config SND_SOC_ADAU1977_I2C | |||
322 | select SND_SOC_ADAU1977 | 328 | select SND_SOC_ADAU1977 |
323 | select REGMAP_I2C | 329 | select REGMAP_I2C |
324 | 330 | ||
331 | config SND_SOC_ADAU7002 | ||
332 | tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter" | ||
333 | |||
325 | config SND_SOC_ADAV80X | 334 | config SND_SOC_ADAV80X |
326 | tristate | 335 | tristate |
327 | 336 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0f548fd34ca3..e37815d55c10 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o | |||
7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o | 7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o |
8 | snd-soc-ad1980-objs := ad1980.o | 8 | snd-soc-ad1980-objs := ad1980.o |
9 | snd-soc-ad73311-objs := ad73311.o | 9 | snd-soc-ad73311-objs := ad73311.o |
10 | snd-soc-adau-utils-objs := adau-utils.o | ||
10 | snd-soc-adau1373-objs := adau1373.o | 11 | snd-soc-adau1373-objs := adau1373.o |
11 | snd-soc-adau1701-objs := adau1701.o | 12 | snd-soc-adau1701-objs := adau1701.o |
12 | snd-soc-adau17x1-objs := adau17x1.o | 13 | snd-soc-adau17x1-objs := adau17x1.o |
@@ -19,6 +20,7 @@ snd-soc-adau1781-spi-objs := adau1781-spi.o | |||
19 | snd-soc-adau1977-objs := adau1977.o | 20 | snd-soc-adau1977-objs := adau1977.o |
20 | snd-soc-adau1977-spi-objs := adau1977-spi.o | 21 | snd-soc-adau1977-spi-objs := adau1977-spi.o |
21 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o | 22 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o |
23 | snd-soc-adau7002-objs := adau7002.o | ||
22 | snd-soc-adav80x-objs := adav80x.o | 24 | snd-soc-adav80x-objs := adav80x.o |
23 | snd-soc-adav801-objs := adav801.o | 25 | snd-soc-adav801-objs := adav801.o |
24 | snd-soc-adav803-objs := adav803.o | 26 | snd-soc-adav803-objs := adav803.o |
@@ -220,6 +222,7 @@ obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o | |||
220 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o | 222 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o |
221 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 223 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
222 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 224 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
225 | obj-$(CONFIG_SND_SOC_ADAU_UTILS) += snd-soc-adau-utils.o | ||
223 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o | 226 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o |
224 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o | 227 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o |
225 | obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o | 228 | obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o |
@@ -232,6 +235,7 @@ obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o | |||
232 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o | 235 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o |
233 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o | 236 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o |
234 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o | 237 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o |
238 | obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o | ||
235 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | 239 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o |
236 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o | 240 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o |
237 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o | 241 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o |
diff --git a/sound/soc/codecs/adau-utils.c b/sound/soc/codecs/adau-utils.c new file mode 100644 index 000000000000..19d6a6f41b12 --- /dev/null +++ b/sound/soc/codecs/adau-utils.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Shared helper functions for devices from the ADAU family | ||
3 | * | ||
4 | * Copyright 2011-2016 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2 or later. | ||
8 | */ | ||
9 | |||
10 | #include <linux/gcd.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include "adau-utils.h" | ||
15 | |||
16 | int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, | ||
17 | uint8_t regs[5]) | ||
18 | { | ||
19 | unsigned int r, n, m, i, j; | ||
20 | unsigned int div; | ||
21 | |||
22 | if (!freq_out) { | ||
23 | r = 0; | ||
24 | n = 0; | ||
25 | m = 0; | ||
26 | div = 0; | ||
27 | } else { | ||
28 | if (freq_out % freq_in != 0) { | ||
29 | div = DIV_ROUND_UP(freq_in, 13500000); | ||
30 | freq_in /= div; | ||
31 | r = freq_out / freq_in; | ||
32 | i = freq_out % freq_in; | ||
33 | j = gcd(i, freq_in); | ||
34 | n = i / j; | ||
35 | m = freq_in / j; | ||
36 | div--; | ||
37 | } else { | ||
38 | r = freq_out / freq_in; | ||
39 | n = 0; | ||
40 | m = 0; | ||
41 | div = 0; | ||
42 | } | ||
43 | if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | |||
47 | regs[0] = m >> 8; | ||
48 | regs[1] = m & 0xff; | ||
49 | regs[2] = n >> 8; | ||
50 | regs[3] = n & 0xff; | ||
51 | regs[4] = (r << 3) | (div << 1); | ||
52 | if (m != 0) | ||
53 | regs[4] |= 1; /* Fractional mode */ | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(adau_calc_pll_cfg); | ||
58 | |||
59 | MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions"); | ||
60 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
61 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/adau-utils.h b/sound/soc/codecs/adau-utils.h new file mode 100644 index 000000000000..939b5f37762f --- /dev/null +++ b/sound/soc/codecs/adau-utils.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef SOUND_SOC_CODECS_ADAU_PLL_H | ||
2 | #define SOUND_SOC_CODECS_ADAU_PLL_H | ||
3 | |||
4 | int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, | ||
5 | uint8_t regs[5]); | ||
6 | |||
7 | #endif | ||
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index fe1353a797b9..1556b360fa15 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/adau1373.h> | 23 | #include <sound/adau1373.h> |
24 | 24 | ||
25 | #include "adau1373.h" | 25 | #include "adau1373.h" |
26 | #include "adau-utils.h" | ||
26 | 27 | ||
27 | struct adau1373_dai { | 28 | struct adau1373_dai { |
28 | unsigned int clk_src; | 29 | unsigned int clk_src; |
@@ -1254,7 +1255,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1254 | { | 1255 | { |
1255 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 1256 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
1256 | unsigned int dpll_div = 0; | 1257 | unsigned int dpll_div = 0; |
1257 | unsigned int x, r, n, m, i, j, mode; | 1258 | uint8_t pll_regs[5]; |
1259 | int ret; | ||
1258 | 1260 | ||
1259 | switch (pll_id) { | 1261 | switch (pll_id) { |
1260 | case ADAU1373_PLL1: | 1262 | case ADAU1373_PLL1: |
@@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1295 | dpll_div++; | 1297 | dpll_div++; |
1296 | } | 1298 | } |
1297 | 1299 | ||
1298 | if (freq_out % freq_in != 0) { | 1300 | ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs); |
1299 | /* fout = fin * (r + (n/m)) / x */ | 1301 | if (ret) |
1300 | x = DIV_ROUND_UP(freq_in, 13500000); | ||
1301 | freq_in /= x; | ||
1302 | r = freq_out / freq_in; | ||
1303 | i = freq_out % freq_in; | ||
1304 | j = gcd(i, freq_in); | ||
1305 | n = i / j; | ||
1306 | m = freq_in / j; | ||
1307 | x--; | ||
1308 | mode = 1; | ||
1309 | } else { | ||
1310 | /* fout = fin / r */ | ||
1311 | r = freq_out / freq_in; | ||
1312 | n = 0; | ||
1313 | m = 0; | ||
1314 | x = 0; | ||
1315 | mode = 0; | ||
1316 | } | ||
1317 | |||
1318 | if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff) | ||
1319 | return -EINVAL; | 1302 | return -EINVAL; |
1320 | 1303 | ||
1321 | if (dpll_div) { | 1304 | if (dpll_div) { |
@@ -1330,12 +1313,11 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1330 | 1313 | ||
1331 | regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), | 1314 | regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), |
1332 | (source << 4) | dpll_div); | 1315 | (source << 4) | dpll_div); |
1333 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); | 1316 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]); |
1334 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); | 1317 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]); |
1335 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); | 1318 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]); |
1336 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); | 1319 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]); |
1337 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), | 1320 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]); |
1338 | (r << 3) | (x << 1) | mode); | ||
1339 | 1321 | ||
1340 | /* Set sysclk to pll_rate / 4 */ | 1322 | /* Set sysclk to pll_rate / 4 */ |
1341 | regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); | 1323 | regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); |
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 8de010f758cd..9e7f257f17f8 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c | |||
@@ -31,7 +31,7 @@ static int adau1761_i2c_probe(struct i2c_client *client, | |||
31 | 31 | ||
32 | static int adau1761_i2c_remove(struct i2c_client *client) | 32 | static int adau1761_i2c_remove(struct i2c_client *client) |
33 | { | 33 | { |
34 | snd_soc_unregister_codec(&client->dev); | 34 | adau17x1_remove(&client->dev); |
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index d9171245bd9f..a0b214be759a 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c | |||
@@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi) | |||
48 | 48 | ||
49 | static int adau1761_spi_remove(struct spi_device *spi) | 49 | static int adau1761_spi_remove(struct spi_device *spi) |
50 | { | 50 | { |
51 | snd_soc_unregister_codec(&spi->dev); | 51 | adau17x1_remove(&spi->dev); |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 06cbca84cf02..7b9d1802d159 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c | |||
@@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client, | |||
31 | 31 | ||
32 | static int adau1781_i2c_remove(struct i2c_client *client) | 32 | static int adau1781_i2c_remove(struct i2c_client *client) |
33 | { | 33 | { |
34 | snd_soc_unregister_codec(&client->dev); | 34 | adau17x1_remove(&client->dev); |
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index 3d965a01b99c..9b233544d2e8 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c | |||
@@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi) | |||
48 | 48 | ||
49 | static int adau1781_spi_remove(struct spi_device *spi) | 49 | static int adau1781_spi_remove(struct spi_device *spi) |
50 | { | 50 | { |
51 | snd_soc_unregister_codec(&spi->dev); | 51 | adau17x1_remove(&spi->dev); |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index fcf05b254ecd..439aa3ff1f99 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/clk.h> | ||
12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
14 | #include <sound/core.h> | 15 | #include <sound/core.h> |
@@ -23,6 +24,7 @@ | |||
23 | 24 | ||
24 | #include "sigmadsp.h" | 25 | #include "sigmadsp.h" |
25 | #include "adau17x1.h" | 26 | #include "adau17x1.h" |
27 | #include "adau-utils.h" | ||
26 | 28 | ||
27 | static const char * const adau17x1_capture_mixer_boost_text[] = { | 29 | static const char * const adau17x1_capture_mixer_boost_text[] = { |
28 | "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", | 30 | "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", |
@@ -302,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau) | |||
302 | } | 304 | } |
303 | EXPORT_SYMBOL_GPL(adau17x1_has_dsp); | 305 | EXPORT_SYMBOL_GPL(adau17x1_has_dsp); |
304 | 306 | ||
307 | static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, | ||
308 | int source, unsigned int freq_in, unsigned int freq_out) | ||
309 | { | ||
310 | struct snd_soc_codec *codec = dai->codec; | ||
311 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
312 | int ret; | ||
313 | |||
314 | if (freq_in < 8000000 || freq_in > 27000000) | ||
315 | return -EINVAL; | ||
316 | |||
317 | ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | |||
321 | /* The PLL register is 6 bytes long and can only be written at once. */ | ||
322 | ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, | ||
323 | adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); | ||
324 | if (ret) | ||
325 | return ret; | ||
326 | |||
327 | adau->pll_freq = freq_out; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, | ||
333 | int clk_id, unsigned int freq, int dir) | ||
334 | { | ||
335 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec); | ||
336 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
337 | bool is_pll; | ||
338 | bool was_pll; | ||
339 | |||
340 | switch (clk_id) { | ||
341 | case ADAU17X1_CLK_SRC_MCLK: | ||
342 | is_pll = false; | ||
343 | break; | ||
344 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
345 | if (!adau->mclk) | ||
346 | return -EINVAL; | ||
347 | /* Fall-through */ | ||
348 | case ADAU17X1_CLK_SRC_PLL: | ||
349 | is_pll = true; | ||
350 | break; | ||
351 | default: | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | switch (adau->clk_src) { | ||
356 | case ADAU17X1_CLK_SRC_MCLK: | ||
357 | was_pll = false; | ||
358 | break; | ||
359 | case ADAU17X1_CLK_SRC_PLL: | ||
360 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
361 | was_pll = true; | ||
362 | break; | ||
363 | default: | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | adau->sysclk = freq; | ||
368 | |||
369 | if (is_pll != was_pll) { | ||
370 | if (is_pll) { | ||
371 | snd_soc_dapm_add_routes(dapm, | ||
372 | &adau17x1_dapm_pll_route, 1); | ||
373 | } else { | ||
374 | snd_soc_dapm_del_routes(dapm, | ||
375 | &adau17x1_dapm_pll_route, 1); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | adau->clk_src = clk_id; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int adau17x1_auto_pll(struct snd_soc_dai *dai, | ||
385 | struct snd_pcm_hw_params *params) | ||
386 | { | ||
387 | struct adau *adau = snd_soc_dai_get_drvdata(dai); | ||
388 | unsigned int pll_rate; | ||
389 | |||
390 | switch (params_rate(params)) { | ||
391 | case 48000: | ||
392 | case 8000: | ||
393 | case 12000: | ||
394 | case 16000: | ||
395 | case 24000: | ||
396 | case 32000: | ||
397 | case 96000: | ||
398 | pll_rate = 48000 * 1024; | ||
399 | break; | ||
400 | case 44100: | ||
401 | case 7350: | ||
402 | case 11025: | ||
403 | case 14700: | ||
404 | case 22050: | ||
405 | case 29400: | ||
406 | case 88200: | ||
407 | pll_rate = 44100 * 1024; | ||
408 | break; | ||
409 | default: | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK, | ||
414 | clk_get_rate(adau->mclk), pll_rate); | ||
415 | } | ||
416 | |||
305 | static int adau17x1_hw_params(struct snd_pcm_substream *substream, | 417 | static int adau17x1_hw_params(struct snd_pcm_substream *substream, |
306 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 418 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
307 | { | 419 | { |
@@ -311,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
311 | unsigned int freq; | 423 | unsigned int freq; |
312 | int ret; | 424 | int ret; |
313 | 425 | ||
314 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) | 426 | switch (adau->clk_src) { |
427 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
428 | ret = adau17x1_auto_pll(dai, params); | ||
429 | if (ret) | ||
430 | return ret; | ||
431 | /* Fall-through */ | ||
432 | case ADAU17X1_CLK_SRC_PLL: | ||
315 | freq = adau->pll_freq; | 433 | freq = adau->pll_freq; |
316 | else | 434 | break; |
435 | default: | ||
317 | freq = adau->sysclk; | 436 | freq = adau->sysclk; |
437 | break; | ||
438 | } | ||
318 | 439 | ||
319 | if (freq % params_rate(params) != 0) | 440 | if (freq % params_rate(params) != 0) |
320 | return -EINVAL; | 441 | return -EINVAL; |
@@ -386,93 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
386 | ADAU17X1_SERIAL_PORT1_DELAY_MASK, val); | 507 | ADAU17X1_SERIAL_PORT1_DELAY_MASK, val); |
387 | } | 508 | } |
388 | 509 | ||
389 | static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, | ||
390 | int source, unsigned int freq_in, unsigned int freq_out) | ||
391 | { | ||
392 | struct snd_soc_codec *codec = dai->codec; | ||
393 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
394 | unsigned int r, n, m, i, j; | ||
395 | unsigned int div; | ||
396 | int ret; | ||
397 | |||
398 | if (freq_in < 8000000 || freq_in > 27000000) | ||
399 | return -EINVAL; | ||
400 | |||
401 | if (!freq_out) { | ||
402 | r = 0; | ||
403 | n = 0; | ||
404 | m = 0; | ||
405 | div = 0; | ||
406 | } else { | ||
407 | if (freq_out % freq_in != 0) { | ||
408 | div = DIV_ROUND_UP(freq_in, 13500000); | ||
409 | freq_in /= div; | ||
410 | r = freq_out / freq_in; | ||
411 | i = freq_out % freq_in; | ||
412 | j = gcd(i, freq_in); | ||
413 | n = i / j; | ||
414 | m = freq_in / j; | ||
415 | div--; | ||
416 | } else { | ||
417 | r = freq_out / freq_in; | ||
418 | n = 0; | ||
419 | m = 0; | ||
420 | div = 0; | ||
421 | } | ||
422 | if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | adau->pll_regs[0] = m >> 8; | ||
427 | adau->pll_regs[1] = m & 0xff; | ||
428 | adau->pll_regs[2] = n >> 8; | ||
429 | adau->pll_regs[3] = n & 0xff; | ||
430 | adau->pll_regs[4] = (r << 3) | (div << 1); | ||
431 | if (m != 0) | ||
432 | adau->pll_regs[4] |= 1; /* Fractional mode */ | ||
433 | |||
434 | /* The PLL register is 6 bytes long and can only be written at once. */ | ||
435 | ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, | ||
436 | adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | |||
440 | adau->pll_freq = freq_out; | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, | ||
446 | int clk_id, unsigned int freq, int dir) | ||
447 | { | ||
448 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec); | ||
449 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
450 | |||
451 | switch (clk_id) { | ||
452 | case ADAU17X1_CLK_SRC_MCLK: | ||
453 | case ADAU17X1_CLK_SRC_PLL: | ||
454 | break; | ||
455 | default: | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | adau->sysclk = freq; | ||
460 | |||
461 | if (adau->clk_src != clk_id) { | ||
462 | if (clk_id == ADAU17X1_CLK_SRC_PLL) { | ||
463 | snd_soc_dapm_add_routes(dapm, | ||
464 | &adau17x1_dapm_pll_route, 1); | ||
465 | } else { | ||
466 | snd_soc_dapm_del_routes(dapm, | ||
467 | &adau17x1_dapm_pll_route, 1); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | adau->clk_src = clk_id; | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, | 510 | static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, |
477 | unsigned int fmt) | 511 | unsigned int fmt) |
478 | { | 512 | { |
@@ -857,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec) | |||
857 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes, | 891 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes, |
858 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); | 892 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); |
859 | } | 893 | } |
894 | |||
895 | if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK) | ||
896 | snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1); | ||
897 | |||
860 | return ret; | 898 | return ret; |
861 | } | 899 | } |
862 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); | 900 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); |
@@ -879,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
879 | const char *firmware_name) | 917 | const char *firmware_name) |
880 | { | 918 | { |
881 | struct adau *adau; | 919 | struct adau *adau; |
920 | int ret; | ||
882 | 921 | ||
883 | if (IS_ERR(regmap)) | 922 | if (IS_ERR(regmap)) |
884 | return PTR_ERR(regmap); | 923 | return PTR_ERR(regmap); |
@@ -887,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
887 | if (!adau) | 926 | if (!adau) |
888 | return -ENOMEM; | 927 | return -ENOMEM; |
889 | 928 | ||
929 | adau->mclk = devm_clk_get(dev, "mclk"); | ||
930 | if (IS_ERR(adau->mclk)) { | ||
931 | if (PTR_ERR(adau->mclk) != -ENOENT) | ||
932 | return PTR_ERR(adau->mclk); | ||
933 | /* Clock is optional (for the driver) */ | ||
934 | adau->mclk = NULL; | ||
935 | } else if (adau->mclk) { | ||
936 | adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO; | ||
937 | |||
938 | /* | ||
939 | * Any valid PLL output rate will work at this point, use one | ||
940 | * that is likely to be chosen later as well. The register will | ||
941 | * be written when the PLL is powered up for the first time. | ||
942 | */ | ||
943 | ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024, | ||
944 | adau->pll_regs); | ||
945 | if (ret < 0) | ||
946 | return ret; | ||
947 | |||
948 | ret = clk_prepare_enable(adau->mclk); | ||
949 | if (ret) | ||
950 | return ret; | ||
951 | } | ||
952 | |||
890 | adau->regmap = regmap; | 953 | adau->regmap = regmap; |
891 | adau->switch_mode = switch_mode; | 954 | adau->switch_mode = switch_mode; |
892 | adau->type = type; | 955 | adau->type = type; |
@@ -910,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
910 | } | 973 | } |
911 | EXPORT_SYMBOL_GPL(adau17x1_probe); | 974 | EXPORT_SYMBOL_GPL(adau17x1_probe); |
912 | 975 | ||
976 | void adau17x1_remove(struct device *dev) | ||
977 | { | ||
978 | struct adau *adau = dev_get_drvdata(dev); | ||
979 | |||
980 | snd_soc_unregister_codec(dev); | ||
981 | if (adau->mclk) | ||
982 | clk_disable_unprepare(adau->mclk); | ||
983 | } | ||
984 | EXPORT_SYMBOL_GPL(adau17x1_remove); | ||
985 | |||
913 | MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code"); | 986 | MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code"); |
914 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 987 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
915 | MODULE_LICENSE("GPL"); | 988 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 5ae87a084d97..bf04b7efee40 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h | |||
@@ -22,13 +22,18 @@ enum adau17x1_pll_src { | |||
22 | }; | 22 | }; |
23 | 23 | ||
24 | enum adau17x1_clk_src { | 24 | enum adau17x1_clk_src { |
25 | /* Automatically configure PLL based on the sample rate */ | ||
26 | ADAU17X1_CLK_SRC_PLL_AUTO, | ||
25 | ADAU17X1_CLK_SRC_MCLK, | 27 | ADAU17X1_CLK_SRC_MCLK, |
26 | ADAU17X1_CLK_SRC_PLL, | 28 | ADAU17X1_CLK_SRC_PLL, |
27 | }; | 29 | }; |
28 | 30 | ||
31 | struct clk; | ||
32 | |||
29 | struct adau { | 33 | struct adau { |
30 | unsigned int sysclk; | 34 | unsigned int sysclk; |
31 | unsigned int pll_freq; | 35 | unsigned int pll_freq; |
36 | struct clk *mclk; | ||
32 | 37 | ||
33 | enum adau17x1_clk_src clk_src; | 38 | enum adau17x1_clk_src clk_src; |
34 | enum adau17x1_type type; | 39 | enum adau17x1_type type; |
@@ -52,6 +57,7 @@ int adau17x1_add_routes(struct snd_soc_codec *codec); | |||
52 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 57 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
53 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), | 58 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
54 | const char *firmware_name); | 59 | const char *firmware_name); |
60 | void adau17x1_remove(struct device *dev); | ||
55 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | 61 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, |
56 | enum adau17x1_micbias_voltage micbias); | 62 | enum adau17x1_micbias_voltage micbias); |
57 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); | 63 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); |
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c new file mode 100644 index 000000000000..9df72c6adcca --- /dev/null +++ b/sound/soc/codecs/adau7002.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * ADAU7002 Stereo PDM-to-I2S/TDM converter driver | ||
3 | * | ||
4 | * Copyright 2014-2016 Analog Devices | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include <sound/soc.h> | ||
16 | |||
17 | static const struct snd_soc_dapm_widget adau7002_widgets[] = { | ||
18 | SND_SOC_DAPM_INPUT("PDM_DAT"), | ||
19 | SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0), | ||
20 | }; | ||
21 | |||
22 | static const struct snd_soc_dapm_route adau7002_routes[] = { | ||
23 | { "Capture", NULL, "PDM_DAT" }, | ||
24 | { "Capture", NULL, "IOVDD" }, | ||
25 | }; | ||
26 | |||
27 | static struct snd_soc_dai_driver adau7002_dai = { | ||
28 | .name = "adau7002-hifi", | ||
29 | .capture = { | ||
30 | .stream_name = "Capture", | ||
31 | .channels_min = 2, | ||
32 | .channels_max = 2, | ||
33 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | | ||
35 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | | ||
36 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE, | ||
37 | .sig_bits = 20, | ||
38 | }, | ||
39 | }; | ||
40 | |||
41 | static const struct snd_soc_codec_driver adau7002_codec_driver = { | ||
42 | .dapm_widgets = adau7002_widgets, | ||
43 | .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), | ||
44 | .dapm_routes = adau7002_routes, | ||
45 | .num_dapm_routes = ARRAY_SIZE(adau7002_routes), | ||
46 | }; | ||
47 | |||
48 | static int adau7002_probe(struct platform_device *pdev) | ||
49 | { | ||
50 | return snd_soc_register_codec(&pdev->dev, &adau7002_codec_driver, | ||
51 | &adau7002_dai, 1); | ||
52 | } | ||
53 | |||
54 | static int adau7002_remove(struct platform_device *pdev) | ||
55 | { | ||
56 | snd_soc_unregister_codec(&pdev->dev); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_OF | ||
61 | static const struct of_device_id adau7002_dt_ids[] = { | ||
62 | { .compatible = "adi,adau7002", }, | ||
63 | { } | ||
64 | }; | ||
65 | MODULE_DEVICE_TABLE(of, adau7002_dt_ids); | ||
66 | #endif | ||
67 | |||
68 | static struct platform_driver adau7002_driver = { | ||
69 | .driver = { | ||
70 | .name = "adau7002", | ||
71 | .of_match_table = of_match_ptr(adau7002_dt_ids), | ||
72 | }, | ||
73 | .probe = adau7002_probe, | ||
74 | .remove = adau7002_remove, | ||
75 | }; | ||
76 | module_platform_driver(adau7002_driver); | ||
77 | |||
78 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
79 | MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver"); | ||
80 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 5013d2ba0c10..97798d250f08 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c | |||
@@ -437,15 +437,25 @@ static struct snd_soc_dai_driver ak4613_dai = { | |||
437 | .symmetric_rates = 1, | 437 | .symmetric_rates = 1, |
438 | }; | 438 | }; |
439 | 439 | ||
440 | static int ak4613_resume(struct snd_soc_codec *codec) | 440 | static int ak4613_suspend(struct snd_soc_codec *codec) |
441 | { | 441 | { |
442 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | 442 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); |
443 | 443 | ||
444 | regcache_cache_only(regmap, true); | ||
444 | regcache_mark_dirty(regmap); | 445 | regcache_mark_dirty(regmap); |
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int ak4613_resume(struct snd_soc_codec *codec) | ||
450 | { | ||
451 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
452 | |||
453 | regcache_cache_only(regmap, false); | ||
445 | return regcache_sync(regmap); | 454 | return regcache_sync(regmap); |
446 | } | 455 | } |
447 | 456 | ||
448 | static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { | 457 | static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { |
458 | .suspend = ak4613_suspend, | ||
449 | .resume = ak4613_resume, | 459 | .resume = ak4613_resume, |
450 | .set_bias_level = ak4613_set_bias_level, | 460 | .set_bias_level = ak4613_set_bias_level, |
451 | .controls = ak4613_snd_controls, | 461 | .controls = ak4613_snd_controls, |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 4d8b9e49e8d6..cc941d66ec3d 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -523,15 +523,23 @@ static struct snd_soc_dai_driver ak4642_dai = { | |||
523 | .symmetric_rates = 1, | 523 | .symmetric_rates = 1, |
524 | }; | 524 | }; |
525 | 525 | ||
526 | static int ak4642_resume(struct snd_soc_codec *codec) | 526 | static int ak4642_suspend(struct snd_soc_codec *codec) |
527 | { | 527 | { |
528 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | 528 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); |
529 | 529 | ||
530 | regcache_cache_only(regmap, true); | ||
530 | regcache_mark_dirty(regmap); | 531 | regcache_mark_dirty(regmap); |
531 | regcache_sync(regmap); | ||
532 | return 0; | 532 | return 0; |
533 | } | 533 | } |
534 | 534 | ||
535 | static int ak4642_resume(struct snd_soc_codec *codec) | ||
536 | { | ||
537 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
538 | |||
539 | regcache_cache_only(regmap, false); | ||
540 | regcache_sync(regmap); | ||
541 | return 0; | ||
542 | } | ||
535 | static int ak4642_probe(struct snd_soc_codec *codec) | 543 | static int ak4642_probe(struct snd_soc_codec *codec) |
536 | { | 544 | { |
537 | struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); | 545 | struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); |
@@ -544,6 +552,7 @@ static int ak4642_probe(struct snd_soc_codec *codec) | |||
544 | 552 | ||
545 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { | 553 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { |
546 | .probe = ak4642_probe, | 554 | .probe = ak4642_probe, |
555 | .suspend = ak4642_suspend, | ||
547 | .resume = ak4642_resume, | 556 | .resume = ak4642_resume, |
548 | .set_bias_level = ak4642_set_bias_level, | 557 | .set_bias_level = ak4642_set_bias_level, |
549 | .controls = ak4642_snd_controls, | 558 | .controls = ak4642_snd_controls, |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 664a8c044ffb..7f9ab92ffa91 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -324,6 +324,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec) | |||
324 | } | 324 | } |
325 | EXPORT_SYMBOL_GPL(arizona_init_gpio); | 325 | EXPORT_SYMBOL_GPL(arizona_init_gpio); |
326 | 326 | ||
327 | int arizona_init_notifiers(struct snd_soc_codec *codec) | ||
328 | { | ||
329 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
330 | struct arizona *arizona = priv->arizona; | ||
331 | |||
332 | BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | EXPORT_SYMBOL_GPL(arizona_init_notifiers); | ||
337 | |||
327 | const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | 338 | const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { |
328 | "None", | 339 | "None", |
329 | "Tone Generator 1", | 340 | "Tone Generator 1", |
@@ -2573,6 +2584,30 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, | |||
2573 | } | 2584 | } |
2574 | EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); | 2585 | EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); |
2575 | 2586 | ||
2587 | int arizona_register_notifier(struct snd_soc_codec *codec, | ||
2588 | struct notifier_block *nb, | ||
2589 | int (*notify)(struct notifier_block *nb, | ||
2590 | unsigned long action, void *data)) | ||
2591 | { | ||
2592 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
2593 | struct arizona *arizona = priv->arizona; | ||
2594 | |||
2595 | nb->notifier_call = notify; | ||
2596 | |||
2597 | return blocking_notifier_chain_register(&arizona->notifier, nb); | ||
2598 | } | ||
2599 | EXPORT_SYMBOL_GPL(arizona_register_notifier); | ||
2600 | |||
2601 | int arizona_unregister_notifier(struct snd_soc_codec *codec, | ||
2602 | struct notifier_block *nb) | ||
2603 | { | ||
2604 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
2605 | struct arizona *arizona = priv->arizona; | ||
2606 | |||
2607 | return blocking_notifier_chain_unregister(&arizona->notifier, nb); | ||
2608 | } | ||
2609 | EXPORT_SYMBOL_GPL(arizona_unregister_notifier); | ||
2610 | |||
2576 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); | 2611 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); |
2577 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 2612 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
2578 | MODULE_LICENSE("GPL"); | 2613 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index ce0531b8c632..46862af7665e 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -63,6 +63,9 @@ | |||
63 | #define ARIZONA_DVFS_SR1_RQ 0x001 | 63 | #define ARIZONA_DVFS_SR1_RQ 0x001 |
64 | #define ARIZONA_DVFS_ADSP1_RQ 0x100 | 64 | #define ARIZONA_DVFS_ADSP1_RQ 0x100 |
65 | 65 | ||
66 | /* Notifier events */ | ||
67 | #define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1 | ||
68 | |||
66 | struct arizona; | 69 | struct arizona; |
67 | struct wm_adsp; | 70 | struct wm_adsp; |
68 | 71 | ||
@@ -95,6 +98,10 @@ struct arizona_priv { | |||
95 | bool dvfs_cached; | 98 | bool dvfs_cached; |
96 | }; | 99 | }; |
97 | 100 | ||
101 | struct arizona_voice_trigger_info { | ||
102 | int core; | ||
103 | }; | ||
104 | |||
98 | #define ARIZONA_NUM_MIXER_INPUTS 104 | 105 | #define ARIZONA_NUM_MIXER_INPUTS 104 |
99 | 106 | ||
100 | extern const unsigned int arizona_mixer_tlv[]; | 107 | extern const unsigned int arizona_mixer_tlv[]; |
@@ -306,6 +313,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, | |||
306 | extern int arizona_init_spk(struct snd_soc_codec *codec); | 313 | extern int arizona_init_spk(struct snd_soc_codec *codec); |
307 | extern int arizona_init_gpio(struct snd_soc_codec *codec); | 314 | extern int arizona_init_gpio(struct snd_soc_codec *codec); |
308 | extern int arizona_init_mono(struct snd_soc_codec *codec); | 315 | extern int arizona_init_mono(struct snd_soc_codec *codec); |
316 | extern int arizona_init_notifiers(struct snd_soc_codec *codec); | ||
309 | 317 | ||
310 | extern int arizona_free_spk(struct snd_soc_codec *codec); | 318 | extern int arizona_free_spk(struct snd_soc_codec *codec); |
311 | 319 | ||
@@ -317,4 +325,13 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output, | |||
317 | extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); | 325 | extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); |
318 | 326 | ||
319 | extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); | 327 | extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); |
328 | |||
329 | extern int arizona_register_notifier(struct snd_soc_codec *codec, | ||
330 | struct notifier_block *nb, | ||
331 | int (*notify)(struct notifier_block *nb, | ||
332 | unsigned long action, | ||
333 | void *data)); | ||
334 | extern int arizona_unregister_notifier(struct snd_soc_codec *codec, | ||
335 | struct notifier_block *nb); | ||
336 | |||
320 | #endif | 337 | #endif |
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5ec5a682d186..bbc8cf18ded0 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c | |||
@@ -1067,6 +1067,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
1067 | { | 1067 | { |
1068 | struct cs47l24_priv *priv = data; | 1068 | struct cs47l24_priv *priv = data; |
1069 | struct arizona *arizona = priv->core.arizona; | 1069 | struct arizona *arizona = priv->core.arizona; |
1070 | struct arizona_voice_trigger_info info; | ||
1070 | int serviced = 0; | 1071 | int serviced = 0; |
1071 | int i, ret; | 1072 | int i, ret; |
1072 | 1073 | ||
@@ -1074,6 +1075,12 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
1074 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); | 1075 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); |
1075 | if (ret != -ENODEV) | 1076 | if (ret != -ENODEV) |
1076 | serviced++; | 1077 | serviced++; |
1078 | if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) { | ||
1079 | info.core = i; | ||
1080 | arizona_call_notifiers(arizona, | ||
1081 | ARIZONA_NOTIFY_VOICE_TRIGGER, | ||
1082 | &info); | ||
1083 | } | ||
1077 | } | 1084 | } |
1078 | 1085 | ||
1079 | if (!serviced) { | 1086 | if (!serviced) { |
@@ -1096,6 +1103,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) | |||
1096 | arizona_init_spk(codec); | 1103 | arizona_init_spk(codec); |
1097 | arizona_init_gpio(codec); | 1104 | arizona_init_gpio(codec); |
1098 | arizona_init_mono(codec); | 1105 | arizona_init_mono(codec); |
1106 | arizona_init_notifiers(codec); | ||
1099 | 1107 | ||
1100 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, | 1108 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, |
1101 | "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, | 1109 | "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, |
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index d54f1b46c9ec..1aac0e1122cf 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -2223,6 +2223,7 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) | |||
2223 | { | 2223 | { |
2224 | struct wm5110_priv *priv = data; | 2224 | struct wm5110_priv *priv = data; |
2225 | struct arizona *arizona = priv->core.arizona; | 2225 | struct arizona *arizona = priv->core.arizona; |
2226 | struct arizona_voice_trigger_info info; | ||
2226 | int serviced = 0; | 2227 | int serviced = 0; |
2227 | int i, ret; | 2228 | int i, ret; |
2228 | 2229 | ||
@@ -2230,6 +2231,12 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) | |||
2230 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); | 2231 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); |
2231 | if (ret != -ENODEV) | 2232 | if (ret != -ENODEV) |
2232 | serviced++; | 2233 | serviced++; |
2234 | if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) { | ||
2235 | info.core = i; | ||
2236 | arizona_call_notifiers(arizona, | ||
2237 | ARIZONA_NOTIFY_VOICE_TRIGGER, | ||
2238 | &info); | ||
2239 | } | ||
2233 | } | 2240 | } |
2234 | 2241 | ||
2235 | if (!serviced) { | 2242 | if (!serviced) { |
@@ -2252,6 +2259,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) | |||
2252 | arizona_init_spk(codec); | 2259 | arizona_init_spk(codec); |
2253 | arizona_init_gpio(codec); | 2260 | arizona_init_gpio(codec); |
2254 | arizona_init_mono(codec); | 2261 | arizona_init_mono(codec); |
2262 | arizona_init_notifiers(codec); | ||
2255 | 2263 | ||
2256 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, | 2264 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, |
2257 | "ADSP2 Compressed IRQ", wm5110_adsp2_irq, | 2265 | "ADSP2 Compressed IRQ", wm5110_adsp2_irq, |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a07bd7c2c587..f6eb2e5b2c07 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -2366,13 +2366,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
2366 | dsp->running = false; | 2366 | dsp->running = false; |
2367 | 2367 | ||
2368 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 2368 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
2369 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | | 2369 | ADSP2_CORE_ENA | ADSP2_START, 0); |
2370 | ADSP2_START, 0); | ||
2371 | 2370 | ||
2372 | /* Make sure DMAs are quiesced */ | 2371 | /* Make sure DMAs are quiesced */ |
2372 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); | ||
2373 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); | 2373 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
2374 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); | 2374 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); |
2375 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); | 2375 | |
2376 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | ||
2377 | ADSP2_SYS_ENA, 0); | ||
2376 | 2378 | ||
2377 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2379 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
2378 | ctl->enabled = 0; | 2380 | ctl->enabled = 0; |
@@ -3037,12 +3039,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
3037 | 3039 | ||
3038 | buf = compr->buf; | 3040 | buf = compr->buf; |
3039 | 3041 | ||
3040 | if (!compr->buf) { | 3042 | if (!compr->buf || compr->buf->error) { |
3041 | ret = -ENXIO; | 3043 | snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); |
3042 | goto out; | ||
3043 | } | ||
3044 | |||
3045 | if (compr->buf->error) { | ||
3046 | ret = -EIO; | 3044 | ret = -EIO; |
3047 | goto out; | 3045 | goto out; |
3048 | } | 3046 | } |
@@ -3060,8 +3058,12 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
3060 | */ | 3058 | */ |
3061 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { | 3059 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
3062 | ret = wm_adsp_buffer_get_error(buf); | 3060 | ret = wm_adsp_buffer_get_error(buf); |
3063 | if (ret < 0) | 3061 | if (ret < 0) { |
3062 | if (compr->buf->error) | ||
3063 | snd_compr_stop_error(stream, | ||
3064 | SNDRV_PCM_STATE_XRUN); | ||
3064 | goto out; | 3065 | goto out; |
3066 | } | ||
3065 | 3067 | ||
3066 | ret = wm_adsp_buffer_reenable_irq(buf); | 3068 | ret = wm_adsp_buffer_reenable_irq(buf); |
3067 | if (ret < 0) { | 3069 | if (ret < 0) { |
@@ -3156,11 +3158,10 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, | |||
3156 | 3158 | ||
3157 | adsp_dbg(dsp, "Requested read of %zu bytes\n", count); | 3159 | adsp_dbg(dsp, "Requested read of %zu bytes\n", count); |
3158 | 3160 | ||
3159 | if (!compr->buf) | 3161 | if (!compr->buf || compr->buf->error) { |
3160 | return -ENXIO; | 3162 | snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); |
3161 | |||
3162 | if (compr->buf->error) | ||
3163 | return -EIO; | 3163 | return -EIO; |
3164 | } | ||
3164 | 3165 | ||
3165 | count /= WM_ADSP_DATA_WORD_SIZE; | 3166 | count /= WM_ADSP_DATA_WORD_SIZE; |
3166 | 3167 | ||