aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/rt5514-spi.c459
-rw-r--r--sound/soc/codecs/rt5514-spi.h38
-rw-r--r--sound/soc/codecs/rt5514.c136
-rw-r--r--sound/soc/codecs/rt5514.h4
6 files changed, 640 insertions, 2 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4d82a58ff6b0..7d5afd1ea09b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -643,6 +643,9 @@ config SND_SOC_RT298
643config SND_SOC_RT5514 643config SND_SOC_RT5514
644 tristate 644 tristate
645 645
646config SND_SOC_RT5514_SPI
647 tristate
648
646config SND_SOC_RT5616 649config SND_SOC_RT5616
647 tristate "Realtek RT5616 CODEC" 650 tristate "Realtek RT5616 CODEC"
648 depends on I2C 651 depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0f548fd34ca3..734b68de246c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -100,6 +100,7 @@ snd-soc-rl6347a-objs := rl6347a.o
100snd-soc-rt286-objs := rt286.o 100snd-soc-rt286-objs := rt286.o
101snd-soc-rt298-objs := rt298.o 101snd-soc-rt298-objs := rt298.o
102snd-soc-rt5514-objs := rt5514.o 102snd-soc-rt5514-objs := rt5514.o
103snd-soc-rt5514-spi-objs := rt5514-spi.o
103snd-soc-rt5616-objs := rt5616.o 104snd-soc-rt5616-objs := rt5616.o
104snd-soc-rt5631-objs := rt5631.o 105snd-soc-rt5631-objs := rt5631.o
105snd-soc-rt5640-objs := rt5640.o 106snd-soc-rt5640-objs := rt5640.o
@@ -314,6 +315,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
314obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o 315obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
315obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o 316obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
316obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o 317obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
318obj-$(CONFIG_SND_SOC_RT5514_SPI) += snd-soc-rt5514-spi.o
317obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o 319obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
318obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 320obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
319obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o 321obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
new file mode 100644
index 000000000000..8a9382e9787a
--- /dev/null
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -0,0 +1,459 @@
1/*
2 * rt5514-spi.c -- RT5514 SPI driver
3 *
4 * Copyright 2015 Realtek Semiconductor Corp.
5 * Author: Oder Chiou <oder_chiou@realtek.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/input.h>
14#include <linux/spi/spi.h>
15#include <linux/device.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/interrupt.h>
19#include <linux/irq.h>
20#include <linux/slab.h>
21#include <linux/gpio.h>
22#include <linux/sched.h>
23#include <linux/kthread.h>
24#include <linux/uaccess.h>
25#include <linux/miscdevice.h>
26#include <linux/regulator/consumer.h>
27#include <linux/pm_qos.h>
28#include <linux/sysfs.h>
29#include <linux/clk.h>
30#include <sound/core.h>
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc.h>
34#include <sound/soc-dapm.h>
35#include <sound/initval.h>
36#include <sound/tlv.h>
37
38#include "rt5514-spi.h"
39
40static struct spi_device *rt5514_spi;
41
42struct rt5514_dsp {
43 struct device *dev;
44 struct delayed_work copy_work;
45 struct mutex dma_lock;
46 struct snd_pcm_substream *substream;
47 unsigned int buf_base, buf_limit, buf_rp;
48 size_t buf_size;
49 size_t dma_offset;
50 size_t dsp_offset;
51};
52
53static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = {
54 .info = SNDRV_PCM_INFO_MMAP |
55 SNDRV_PCM_INFO_MMAP_VALID |
56 SNDRV_PCM_INFO_INTERLEAVED,
57 .formats = SNDRV_PCM_FMTBIT_S16_LE,
58 .period_bytes_min = PAGE_SIZE,
59 .period_bytes_max = 0x20000 / 8,
60 .periods_min = 8,
61 .periods_max = 8,
62 .channels_min = 1,
63 .channels_max = 1,
64 .buffer_bytes_max = 0x20000,
65};
66
67static struct snd_soc_dai_driver rt5514_spi_dai = {
68 .name = "rt5514-dsp-cpu-dai",
69 .id = 0,
70 .capture = {
71 .stream_name = "DSP Capture",
72 .channels_min = 1,
73 .channels_max = 1,
74 .rates = SNDRV_PCM_RATE_16000,
75 .formats = SNDRV_PCM_FMTBIT_S16_LE,
76 },
77};
78
79static void rt5514_spi_copy_work(struct work_struct *work)
80{
81 struct rt5514_dsp *rt5514_dsp =
82 container_of(work, struct rt5514_dsp, copy_work.work);
83 struct snd_pcm_runtime *runtime = rt5514_dsp->substream->runtime;
84 size_t period_bytes, truncated_bytes = 0;
85
86 mutex_lock(&rt5514_dsp->dma_lock);
87 if (!rt5514_dsp->substream) {
88 dev_err(rt5514_dsp->dev, "No pcm substream\n");
89 goto done;
90 }
91
92 period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
93
94 if (rt5514_dsp->buf_size - rt5514_dsp->dsp_offset < period_bytes)
95 period_bytes = rt5514_dsp->buf_size - rt5514_dsp->dsp_offset;
96
97 if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) {
98 rt5514_spi_burst_read(rt5514_dsp->buf_rp,
99 runtime->dma_area + rt5514_dsp->dma_offset,
100 period_bytes);
101
102 if (rt5514_dsp->buf_rp + period_bytes == rt5514_dsp->buf_limit)
103 rt5514_dsp->buf_rp = rt5514_dsp->buf_base;
104 else
105 rt5514_dsp->buf_rp += period_bytes;
106 } else {
107 truncated_bytes = rt5514_dsp->buf_limit - rt5514_dsp->buf_rp;
108 rt5514_spi_burst_read(rt5514_dsp->buf_rp,
109 runtime->dma_area + rt5514_dsp->dma_offset,
110 truncated_bytes);
111
112 rt5514_spi_burst_read(rt5514_dsp->buf_base,
113 runtime->dma_area + rt5514_dsp->dma_offset +
114 truncated_bytes, period_bytes - truncated_bytes);
115
116 rt5514_dsp->buf_rp = rt5514_dsp->buf_base +
117 period_bytes - truncated_bytes;
118 }
119
120 rt5514_dsp->dma_offset += period_bytes;
121 if (rt5514_dsp->dma_offset >= runtime->dma_bytes)
122 rt5514_dsp->dma_offset = 0;
123
124 rt5514_dsp->dsp_offset += period_bytes;
125
126 snd_pcm_period_elapsed(rt5514_dsp->substream);
127
128 if (rt5514_dsp->dsp_offset < rt5514_dsp->buf_size)
129 schedule_delayed_work(&rt5514_dsp->copy_work, 5);
130done:
131 mutex_unlock(&rt5514_dsp->dma_lock);
132}
133
134/* PCM for streaming audio from the DSP buffer */
135static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream)
136{
137 snd_soc_set_runtime_hwparams(substream, &rt5514_spi_pcm_hardware);
138
139 return 0;
140}
141
142static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *hw_params)
144{
145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 struct rt5514_dsp *rt5514_dsp =
147 snd_soc_platform_get_drvdata(rtd->platform);
148 int ret;
149
150 mutex_lock(&rt5514_dsp->dma_lock);
151 ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
152 params_buffer_bytes(hw_params));
153 rt5514_dsp->substream = substream;
154 mutex_unlock(&rt5514_dsp->dma_lock);
155
156 return ret;
157}
158
159static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
160{
161 struct snd_soc_pcm_runtime *rtd = substream->private_data;
162 struct rt5514_dsp *rt5514_dsp =
163 snd_soc_platform_get_drvdata(rtd->platform);
164
165 mutex_lock(&rt5514_dsp->dma_lock);
166 rt5514_dsp->substream = NULL;
167 mutex_unlock(&rt5514_dsp->dma_lock);
168
169 cancel_delayed_work_sync(&rt5514_dsp->copy_work);
170
171 return snd_pcm_lib_free_vmalloc_buffer(substream);
172}
173
174static int rt5514_spi_prepare(struct snd_pcm_substream *substream)
175{
176 struct snd_soc_pcm_runtime *rtd = substream->private_data;
177 struct rt5514_dsp *rt5514_dsp =
178 snd_soc_platform_get_drvdata(rtd->platform);
179 u8 buf[8];
180
181 rt5514_dsp->dma_offset = 0;
182 rt5514_dsp->dsp_offset = 0;
183
184 /**
185 * The address area x1800XXXX is the register address, and it cannot
186 * support spi burst read perfectly. So we use the spi burst read
187 * individually to make sure the data correctly.
188 */
189 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
190 sizeof(buf));
191 rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
192 buf[3] << 24;
193
194 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
195 sizeof(buf));
196 rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
197 buf[3] << 24;
198
199 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP, (u8 *)&buf,
200 sizeof(buf));
201 rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
202 buf[3] << 24;
203
204 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE, (u8 *)&buf,
205 sizeof(buf));
206 rt5514_dsp->buf_size = buf[0] | buf[1] << 8 | buf[2] << 16 |
207 buf[3] << 24;
208
209 return 0;
210}
211
212static int rt5514_spi_trigger(struct snd_pcm_substream *substream, int cmd)
213{
214 struct snd_soc_pcm_runtime *rtd = substream->private_data;
215 struct rt5514_dsp *rt5514_dsp =
216 snd_soc_platform_get_drvdata(rtd->platform);
217
218 if (cmd == SNDRV_PCM_TRIGGER_START) {
219 if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
220 rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
221 schedule_delayed_work(&rt5514_dsp->copy_work, 0);
222 }
223
224 return 0;
225}
226
227static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
228 struct snd_pcm_substream *substream)
229{
230 struct snd_pcm_runtime *runtime = substream->runtime;
231 struct snd_soc_pcm_runtime *rtd = substream->private_data;
232 struct rt5514_dsp *rt5514_dsp =
233 snd_soc_platform_get_drvdata(rtd->platform);
234
235 return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
236}
237
238static struct snd_pcm_ops rt5514_spi_pcm_ops = {
239 .open = rt5514_spi_pcm_open,
240 .hw_params = rt5514_spi_hw_params,
241 .hw_free = rt5514_spi_hw_free,
242 .trigger = rt5514_spi_trigger,
243 .prepare = rt5514_spi_prepare,
244 .pointer = rt5514_spi_pcm_pointer,
245 .mmap = snd_pcm_lib_mmap_vmalloc,
246 .page = snd_pcm_lib_get_vmalloc_page,
247};
248
249static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
250{
251 struct rt5514_dsp *rt5514_dsp;
252
253 rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp),
254 GFP_KERNEL);
255
256 rt5514_dsp->dev = &rt5514_spi->dev;
257 mutex_init(&rt5514_dsp->dma_lock);
258 INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work);
259 snd_soc_platform_set_drvdata(platform, rt5514_dsp);
260
261 return 0;
262}
263
264static struct snd_soc_platform_driver rt5514_spi_platform = {
265 .probe = rt5514_spi_pcm_probe,
266 .ops = &rt5514_spi_pcm_ops,
267};
268
269static const struct snd_soc_component_driver rt5514_spi_dai_component = {
270 .name = "rt5514-spi-dai",
271};
272
273/**
274 * rt5514_spi_burst_read - Read data from SPI by rt5514 address.
275 * @addr: Start address.
276 * @rxbuf: Data Buffer for reading.
277 * @len: Data length, it must be a multiple of 8.
278 *
279 *
280 * Returns true for success.
281 */
282int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len)
283{
284 u8 spi_cmd = RT5514_SPI_CMD_BURST_READ;
285 int status;
286 u8 write_buf[8];
287 unsigned int i, end, offset = 0;
288
289 struct spi_message message;
290 struct spi_transfer x[3];
291
292 while (offset < len) {
293 if (offset + RT5514_SPI_BUF_LEN <= len)
294 end = RT5514_SPI_BUF_LEN;
295 else
296 end = len % RT5514_SPI_BUF_LEN;
297
298 write_buf[0] = spi_cmd;
299 write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
300 write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
301 write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
302 write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
303
304 spi_message_init(&message);
305 memset(x, 0, sizeof(x));
306
307 x[0].len = 5;
308 x[0].tx_buf = write_buf;
309 spi_message_add_tail(&x[0], &message);
310
311 x[1].len = 4;
312 x[1].tx_buf = write_buf;
313 spi_message_add_tail(&x[1], &message);
314
315 x[2].len = end;
316 x[2].rx_buf = rxbuf + offset;
317 spi_message_add_tail(&x[2], &message);
318
319 status = spi_sync(rt5514_spi, &message);
320
321 if (status)
322 return false;
323
324 offset += RT5514_SPI_BUF_LEN;
325 }
326
327 for (i = 0; i < len; i += 8) {
328 write_buf[0] = rxbuf[i + 0];
329 write_buf[1] = rxbuf[i + 1];
330 write_buf[2] = rxbuf[i + 2];
331 write_buf[3] = rxbuf[i + 3];
332 write_buf[4] = rxbuf[i + 4];
333 write_buf[5] = rxbuf[i + 5];
334 write_buf[6] = rxbuf[i + 6];
335 write_buf[7] = rxbuf[i + 7];
336
337 rxbuf[i + 0] = write_buf[7];
338 rxbuf[i + 1] = write_buf[6];
339 rxbuf[i + 2] = write_buf[5];
340 rxbuf[i + 3] = write_buf[4];
341 rxbuf[i + 4] = write_buf[3];
342 rxbuf[i + 5] = write_buf[2];
343 rxbuf[i + 6] = write_buf[1];
344 rxbuf[i + 7] = write_buf[0];
345 }
346
347 return true;
348}
349
350/**
351 * rt5514_spi_burst_write - Write data to SPI by rt5514 address.
352 * @addr: Start address.
353 * @txbuf: Data Buffer for writng.
354 * @len: Data length, it must be a multiple of 8.
355 *
356 *
357 * Returns true for success.
358 */
359int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len)
360{
361 u8 spi_cmd = RT5514_SPI_CMD_BURST_WRITE;
362 u8 *write_buf;
363 unsigned int i, end, offset = 0;
364
365 write_buf = kmalloc(RT5514_SPI_BUF_LEN + 6, GFP_KERNEL);
366
367 if (write_buf == NULL)
368 return -ENOMEM;
369
370 while (offset < len) {
371 if (offset + RT5514_SPI_BUF_LEN <= len)
372 end = RT5514_SPI_BUF_LEN;
373 else
374 end = len % RT5514_SPI_BUF_LEN;
375
376 write_buf[0] = spi_cmd;
377 write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
378 write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
379 write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
380 write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
381
382 for (i = 0; i < end; i += 8) {
383 write_buf[i + 12] = txbuf[offset + i + 0];
384 write_buf[i + 11] = txbuf[offset + i + 1];
385 write_buf[i + 10] = txbuf[offset + i + 2];
386 write_buf[i + 9] = txbuf[offset + i + 3];
387 write_buf[i + 8] = txbuf[offset + i + 4];
388 write_buf[i + 7] = txbuf[offset + i + 5];
389 write_buf[i + 6] = txbuf[offset + i + 6];
390 write_buf[i + 5] = txbuf[offset + i + 7];
391 }
392
393 write_buf[end + 5] = spi_cmd;
394
395 spi_write(rt5514_spi, write_buf, end + 6);
396
397 offset += RT5514_SPI_BUF_LEN;
398 }
399
400 kfree(write_buf);
401
402 return 0;
403}
404EXPORT_SYMBOL_GPL(rt5514_spi_burst_write);
405
406static int rt5514_spi_probe(struct spi_device *spi)
407{
408 int ret;
409
410 rt5514_spi = spi;
411
412 ret = snd_soc_register_platform(&spi->dev, &rt5514_spi_platform);
413 if (ret < 0) {
414 dev_err(&spi->dev, "Failed to register platform.\n");
415 goto err_plat;
416 }
417
418 ret = snd_soc_register_component(&spi->dev, &rt5514_spi_dai_component,
419 &rt5514_spi_dai, 1);
420 if (ret < 0) {
421 dev_err(&spi->dev, "Failed to register component.\n");
422 goto err_comp;
423 }
424
425 return 0;
426err_comp:
427 snd_soc_unregister_platform(&spi->dev);
428err_plat:
429
430 return 0;
431}
432
433static int rt5514_spi_remove(struct spi_device *spi)
434{
435 snd_soc_unregister_component(&spi->dev);
436 snd_soc_unregister_platform(&spi->dev);
437
438 return 0;
439}
440
441static const struct of_device_id rt5514_of_match[] = {
442 { .compatible = "realtek,rt5514", },
443 {},
444};
445MODULE_DEVICE_TABLE(of, rt5514_of_match);
446
447static struct spi_driver rt5514_spi_driver = {
448 .driver = {
449 .name = "rt5514",
450 .of_match_table = of_match_ptr(rt5514_of_match),
451 },
452 .probe = rt5514_spi_probe,
453 .remove = rt5514_spi_remove,
454};
455module_spi_driver(rt5514_spi_driver);
456
457MODULE_DESCRIPTION("RT5514 SPI driver");
458MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
459MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h
new file mode 100644
index 000000000000..f69b1cdf2f9b
--- /dev/null
+++ b/sound/soc/codecs/rt5514-spi.h
@@ -0,0 +1,38 @@
1/*
2 * rt5514-spi.h -- RT5514 driver
3 *
4 * Copyright 2015 Realtek Semiconductor Corp.
5 * Author: Oder Chiou <oder_chiou@realtek.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef __RT5514_SPI_H__
13#define __RT5514_SPI_H__
14
15/**
16 * RT5514_SPI_BUF_LEN is the buffer size of SPI master controller.
17*/
18#define RT5514_SPI_BUF_LEN 240
19
20#define RT5514_BUFFER_VOICE_BASE 0x18001034
21#define RT5514_BUFFER_VOICE_LIMIT 0x18001038
22#define RT5514_BUFFER_VOICE_RP 0x1800103c
23#define RT5514_BUFFER_VOICE_SIZE 0x18001040
24
25/* SPI Command */
26enum {
27 RT5514_SPI_CMD_16_READ = 0,
28 RT5514_SPI_CMD_16_WRITE,
29 RT5514_SPI_CMD_32_READ,
30 RT5514_SPI_CMD_32_WRITE,
31 RT5514_SPI_CMD_BURST_READ,
32 RT5514_SPI_CMD_BURST_WRITE,
33};
34
35int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len);
36int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len);
37
38#endif /* __RT5514_SPI_H__ */
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 879bf60f4965..ecb09891b662 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -30,6 +30,9 @@
30 30
31#include "rl6231.h" 31#include "rl6231.h"
32#include "rt5514.h" 32#include "rt5514.h"
33#if defined(CONFIG_SND_SOC_RT5514_SPI)
34#include "rt5514-spi.h"
35#endif
33 36
34static const struct reg_sequence rt5514_i2c_patch[] = { 37static const struct reg_sequence rt5514_i2c_patch[] = {
35 {0x1800101c, 0x00000000}, 38 {0x1800101c, 0x00000000},
@@ -110,6 +113,35 @@ static const struct reg_default rt5514_reg[] = {
110 {RT5514_VENDOR_ID2, 0x10ec5514}, 113 {RT5514_VENDOR_ID2, 0x10ec5514},
111}; 114};
112 115
116static void rt5514_enable_dsp_prepare(struct rt5514_priv *rt5514)
117{
118 /* Reset */
119 regmap_write(rt5514->i2c_regmap, 0x18002000, 0x000010ec);
120 /* LDO_I_limit */
121 regmap_write(rt5514->i2c_regmap, 0x18002200, 0x00028604);
122 /* I2C bypass enable */
123 regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000001);
124 /* mini-core reset */
125 regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x0005514b);
126 regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x00055149);
127 /* I2C bypass disable */
128 regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000000);
129 /* PIN config */
130 regmap_write(rt5514->i2c_regmap, 0x18002070, 0x00000040);
131 /* PLL3(QN)=RCOSC*(10+2) */
132 regmap_write(rt5514->i2c_regmap, 0x18002240, 0x0000000a);
133 /* PLL3 source=RCOSC, fsi=rt_clk */
134 regmap_write(rt5514->i2c_regmap, 0x18002100, 0x0000000b);
135 /* Power on RCOSC, pll3 */
136 regmap_write(rt5514->i2c_regmap, 0x18002004, 0x00808b81);
137 /* DSP clk source = pll3, ENABLE DSP clk */
138 regmap_write(rt5514->i2c_regmap, 0x18002f08, 0x00000005);
139 /* Enable DSP clk auto switch */
140 regmap_write(rt5514->i2c_regmap, 0x18001114, 0x00000001);
141 /* Reduce DSP power */
142 regmap_write(rt5514->i2c_regmap, 0x18001118, 0x00000001);
143}
144
113static bool rt5514_volatile_register(struct device *dev, unsigned int reg) 145static bool rt5514_volatile_register(struct device *dev, unsigned int reg)
114{ 146{
115 switch (reg) { 147 switch (reg) {
@@ -248,6 +280,74 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv,
248 280
249static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); 281static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
250 282
283static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol,
284 struct snd_ctl_elem_value *ucontrol)
285{
286 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
287 struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
288
289 ucontrol->value.integer.value[0] = rt5514->dsp_enabled;
290
291 return 0;
292}
293
294static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
295 struct snd_ctl_elem_value *ucontrol)
296{
297 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
298 struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
299 struct snd_soc_codec *codec = rt5514->codec;
300 const struct firmware *fw = NULL;
301
302 if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled)
303 return 0;
304
305 if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
306 rt5514->dsp_enabled = ucontrol->value.integer.value[0];
307
308 if (rt5514->dsp_enabled) {
309 rt5514_enable_dsp_prepare(rt5514);
310
311 request_firmware(&fw, RT5514_FIRMWARE1, codec->dev);
312 if (fw) {
313#if defined(CONFIG_SND_SOC_RT5514_SPI)
314 rt5514_spi_burst_write(0x4ff60000, fw->data,
315 ((fw->size/8)+1)*8);
316#else
317 dev_err(codec->dev, "There is no SPI driver for"
318 " loading the firmware\n");
319#endif
320 release_firmware(fw);
321 fw = NULL;
322 }
323
324 request_firmware(&fw, RT5514_FIRMWARE2, codec->dev);
325 if (fw) {
326#if defined(CONFIG_SND_SOC_RT5514_SPI)
327 rt5514_spi_burst_write(0x4ffc0000, fw->data,
328 ((fw->size/8)+1)*8);
329#else
330 dev_err(codec->dev, "There is no SPI driver for"
331 " loading the firmware\n");
332#endif
333 release_firmware(fw);
334 fw = NULL;
335 }
336
337 /* DSP run */
338 regmap_write(rt5514->i2c_regmap, 0x18002f00,
339 0x00055148);
340 } else {
341 regmap_multi_reg_write(rt5514->i2c_regmap,
342 rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
343 regcache_mark_dirty(rt5514->regmap);
344 regcache_sync(rt5514->regmap);
345 }
346 }
347
348 return 0;
349}
350
251static const struct snd_kcontrol_new rt5514_snd_controls[] = { 351static const struct snd_kcontrol_new rt5514_snd_controls[] = {
252 SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, 352 SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
253 RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), 353 RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
@@ -257,6 +357,8 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = {
257 SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, 357 SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1,
258 RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, 358 RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0,
259 adc_vol_tlv), 359 adc_vol_tlv),
360 SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0,
361 rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put),
260}; 362};
261 363
262/* ADC Mixer*/ 364/* ADC Mixer*/
@@ -365,6 +467,35 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
365 return 0; 467 return 0;
366} 468}
367 469
470static int rt5514_pre_event(struct snd_soc_dapm_widget *w,
471 struct snd_kcontrol *kcontrol, int event)
472{
473 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
474 struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
475
476 switch (event) {
477 case SND_SOC_DAPM_PRE_PMU:
478 /**
479 * If the DSP is enabled in start of recording, the DSP
480 * should be disabled, and sync back to normal recording
481 * settings to make sure recording properly.
482 */
483 if (rt5514->dsp_enabled) {
484 rt5514->dsp_enabled = 0;
485 regmap_multi_reg_write(rt5514->i2c_regmap,
486 rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
487 regcache_mark_dirty(rt5514->regmap);
488 regcache_sync(rt5514->regmap);
489 }
490 break;
491
492 default:
493 return 0;
494 }
495
496 return 0;
497}
498
368static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { 499static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
369 /* Input Lines */ 500 /* Input Lines */
370 SND_SOC_DAPM_INPUT("DMIC1L"), 501 SND_SOC_DAPM_INPUT("DMIC1L"),
@@ -472,6 +603,8 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
472 603
473 /* Audio Interface */ 604 /* Audio Interface */
474 SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), 605 SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
606
607 SND_SOC_DAPM_PRE("DAPM Pre", rt5514_pre_event),
475}; 608};
476 609
477static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { 610static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
@@ -871,7 +1004,6 @@ static const struct regmap_config rt5514_i2c_regmap = {
871 .reg_bits = 32, 1004 .reg_bits = 32,
872 .val_bits = 32, 1005 .val_bits = 32,
873 1006
874 .max_register = RT5514_DSP_MAPPING | RT5514_VENDOR_ID2,
875 .readable_reg = rt5514_i2c_readable_register, 1007 .readable_reg = rt5514_i2c_readable_register,
876 1008
877 .cache_type = REGCACHE_NONE, 1009 .cache_type = REGCACHE_NONE,
@@ -944,7 +1076,7 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
944 return -ENODEV; 1076 return -ENODEV;
945 } 1077 }
946 1078
947 ret = regmap_register_patch(rt5514->i2c_regmap, rt5514_i2c_patch, 1079 ret = regmap_multi_reg_write(rt5514->i2c_regmap, rt5514_i2c_patch,
948 ARRAY_SIZE(rt5514_i2c_patch)); 1080 ARRAY_SIZE(rt5514_i2c_patch));
949 if (ret != 0) 1081 if (ret != 0)
950 dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n", 1082 dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n",
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index 6ad8a612f659..6e89e7d46a10 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -225,6 +225,9 @@
225#define RT5514_PLL_INP_MAX 40000000 225#define RT5514_PLL_INP_MAX 40000000
226#define RT5514_PLL_INP_MIN 256000 226#define RT5514_PLL_INP_MIN 256000
227 227
228#define RT5514_FIRMWARE1 "rt5514_dsp_fw1.bin"
229#define RT5514_FIRMWARE2 "rt5514_dsp_fw2.bin"
230
228/* System Clock Source */ 231/* System Clock Source */
229enum { 232enum {
230 RT5514_SCLK_S_MCLK, 233 RT5514_SCLK_S_MCLK,
@@ -247,6 +250,7 @@ struct rt5514_priv {
247 int pll_src; 250 int pll_src;
248 int pll_in; 251 int pll_in;
249 int pll_out; 252 int pll_out;
253 int dsp_enabled;
250}; 254};
251 255
252#endif /* __RT5514_H__ */ 256#endif /* __RT5514_H__ */