2 * rt5514-spi.c -- RT5514 SPI driver
4 * Copyright 2015 Realtek Semiconductor Corp.
5 * Author: Oder Chiou <oder_chiou@realtek.com>
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.
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/uaccess.h>
24 #include <linux/miscdevice.h>
25 #include <linux/regulator/consumer.h>
26 #include <linux/pm_qos.h>
27 #include <linux/sysfs.h>
28 #include <linux/clk.h>
29 #include <sound/core.h>
30 #include <sound/pcm.h>
31 #include <sound/pcm_params.h>
32 #include <sound/soc.h>
33 #include <sound/soc-dapm.h>
34 #include <sound/initval.h>
35 #include <sound/tlv.h>
37 #include "rt5514-spi.h"
39 static struct spi_device
*rt5514_spi
;
43 struct delayed_work copy_work
;
44 struct mutex dma_lock
;
45 struct snd_pcm_substream
*substream
;
46 unsigned int buf_base
, buf_limit
, buf_rp
;
52 static const struct snd_pcm_hardware rt5514_spi_pcm_hardware
= {
53 .info
= SNDRV_PCM_INFO_MMAP
|
54 SNDRV_PCM_INFO_MMAP_VALID
|
55 SNDRV_PCM_INFO_INTERLEAVED
,
56 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
57 .period_bytes_min
= PAGE_SIZE
,
58 .period_bytes_max
= 0x20000 / 8,
63 .buffer_bytes_max
= 0x20000,
66 static struct snd_soc_dai_driver rt5514_spi_dai
= {
67 .name
= "rt5514-dsp-cpu-dai",
70 .stream_name
= "DSP Capture",
73 .rates
= SNDRV_PCM_RATE_16000
,
74 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
78 static void rt5514_spi_copy_work(struct work_struct
*work
)
80 struct rt5514_dsp
*rt5514_dsp
=
81 container_of(work
, struct rt5514_dsp
, copy_work
.work
);
82 struct snd_pcm_runtime
*runtime
;
83 size_t period_bytes
, truncated_bytes
= 0;
85 mutex_lock(&rt5514_dsp
->dma_lock
);
86 if (!rt5514_dsp
->substream
) {
87 dev_err(rt5514_dsp
->dev
, "No pcm substream\n");
91 runtime
= rt5514_dsp
->substream
->runtime
;
92 period_bytes
= snd_pcm_lib_period_bytes(rt5514_dsp
->substream
);
94 if (rt5514_dsp
->buf_size
- rt5514_dsp
->dsp_offset
< period_bytes
)
95 period_bytes
= rt5514_dsp
->buf_size
- rt5514_dsp
->dsp_offset
;
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
,
102 if (rt5514_dsp
->buf_rp
+ period_bytes
== rt5514_dsp
->buf_limit
)
103 rt5514_dsp
->buf_rp
= rt5514_dsp
->buf_base
;
105 rt5514_dsp
->buf_rp
+= period_bytes
;
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
,
112 rt5514_spi_burst_read(rt5514_dsp
->buf_base
,
113 runtime
->dma_area
+ rt5514_dsp
->dma_offset
+
114 truncated_bytes
, period_bytes
- truncated_bytes
);
116 rt5514_dsp
->buf_rp
= rt5514_dsp
->buf_base
+
117 period_bytes
- truncated_bytes
;
120 rt5514_dsp
->dma_offset
+= period_bytes
;
121 if (rt5514_dsp
->dma_offset
>= runtime
->dma_bytes
)
122 rt5514_dsp
->dma_offset
= 0;
124 rt5514_dsp
->dsp_offset
+= period_bytes
;
126 snd_pcm_period_elapsed(rt5514_dsp
->substream
);
128 if (rt5514_dsp
->dsp_offset
< rt5514_dsp
->buf_size
)
129 schedule_delayed_work(&rt5514_dsp
->copy_work
, 5);
131 mutex_unlock(&rt5514_dsp
->dma_lock
);
134 /* PCM for streaming audio from the DSP buffer */
135 static int rt5514_spi_pcm_open(struct snd_pcm_substream
*substream
)
137 snd_soc_set_runtime_hwparams(substream
, &rt5514_spi_pcm_hardware
);
142 static int rt5514_spi_hw_params(struct snd_pcm_substream
*substream
,
143 struct snd_pcm_hw_params
*hw_params
)
145 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
146 struct rt5514_dsp
*rt5514_dsp
=
147 snd_soc_platform_get_drvdata(rtd
->platform
);
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
);
159 static int rt5514_spi_hw_free(struct snd_pcm_substream
*substream
)
161 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
162 struct rt5514_dsp
*rt5514_dsp
=
163 snd_soc_platform_get_drvdata(rtd
->platform
);
165 mutex_lock(&rt5514_dsp
->dma_lock
);
166 rt5514_dsp
->substream
= NULL
;
167 mutex_unlock(&rt5514_dsp
->dma_lock
);
169 cancel_delayed_work_sync(&rt5514_dsp
->copy_work
);
171 return snd_pcm_lib_free_vmalloc_buffer(substream
);
174 static int rt5514_spi_prepare(struct snd_pcm_substream
*substream
)
176 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
177 struct rt5514_dsp
*rt5514_dsp
=
178 snd_soc_platform_get_drvdata(rtd
->platform
);
181 rt5514_dsp
->dma_offset
= 0;
182 rt5514_dsp
->dsp_offset
= 0;
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.
189 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE
, (u8
*)&buf
,
191 rt5514_dsp
->buf_base
= buf
[0] | buf
[1] << 8 | buf
[2] << 16 |
194 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT
, (u8
*)&buf
,
196 rt5514_dsp
->buf_limit
= buf
[0] | buf
[1] << 8 | buf
[2] << 16 |
199 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP
, (u8
*)&buf
,
201 rt5514_dsp
->buf_rp
= buf
[0] | buf
[1] << 8 | buf
[2] << 16 |
204 rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE
, (u8
*)&buf
,
206 rt5514_dsp
->buf_size
= buf
[0] | buf
[1] << 8 | buf
[2] << 16 |
212 static int rt5514_spi_trigger(struct snd_pcm_substream
*substream
, int cmd
)
214 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
215 struct rt5514_dsp
*rt5514_dsp
=
216 snd_soc_platform_get_drvdata(rtd
->platform
);
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);
227 static snd_pcm_uframes_t
rt5514_spi_pcm_pointer(
228 struct snd_pcm_substream
*substream
)
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
);
235 return bytes_to_frames(runtime
, rt5514_dsp
->dma_offset
);
238 static const 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
,
249 static int rt5514_spi_pcm_probe(struct snd_soc_platform
*platform
)
251 struct rt5514_dsp
*rt5514_dsp
;
253 rt5514_dsp
= devm_kzalloc(platform
->dev
, sizeof(*rt5514_dsp
),
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
);
264 static struct snd_soc_platform_driver rt5514_spi_platform
= {
265 .probe
= rt5514_spi_pcm_probe
,
266 .ops
= &rt5514_spi_pcm_ops
,
269 static const struct snd_soc_component_driver rt5514_spi_dai_component
= {
270 .name
= "rt5514-spi-dai",
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.
280 * Returns true for success.
282 int rt5514_spi_burst_read(unsigned int addr
, u8
*rxbuf
, size_t len
)
284 u8 spi_cmd
= RT5514_SPI_CMD_BURST_READ
;
287 unsigned int i
, end
, offset
= 0;
289 struct spi_message message
;
290 struct spi_transfer x
[3];
292 while (offset
< len
) {
293 if (offset
+ RT5514_SPI_BUF_LEN
<= len
)
294 end
= RT5514_SPI_BUF_LEN
;
296 end
= len
% RT5514_SPI_BUF_LEN
;
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;
304 spi_message_init(&message
);
305 memset(x
, 0, sizeof(x
));
308 x
[0].tx_buf
= write_buf
;
309 spi_message_add_tail(&x
[0], &message
);
312 x
[1].tx_buf
= write_buf
;
313 spi_message_add_tail(&x
[1], &message
);
316 x
[2].rx_buf
= rxbuf
+ offset
;
317 spi_message_add_tail(&x
[2], &message
);
319 status
= spi_sync(rt5514_spi
, &message
);
324 offset
+= RT5514_SPI_BUF_LEN
;
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];
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];
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.
357 * Returns true for success.
359 int rt5514_spi_burst_write(u32 addr
, const u8
*txbuf
, size_t len
)
361 u8 spi_cmd
= RT5514_SPI_CMD_BURST_WRITE
;
363 unsigned int i
, end
, offset
= 0;
365 write_buf
= kmalloc(RT5514_SPI_BUF_LEN
+ 6, GFP_KERNEL
);
367 if (write_buf
== NULL
)
370 while (offset
< len
) {
371 if (offset
+ RT5514_SPI_BUF_LEN
<= len
)
372 end
= RT5514_SPI_BUF_LEN
;
374 end
= len
% RT5514_SPI_BUF_LEN
;
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;
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];
393 write_buf
[end
+ 5] = spi_cmd
;
395 spi_write(rt5514_spi
, write_buf
, end
+ 6);
397 offset
+= RT5514_SPI_BUF_LEN
;
404 EXPORT_SYMBOL_GPL(rt5514_spi_burst_write
);
406 static int rt5514_spi_probe(struct spi_device
*spi
)
412 ret
= devm_snd_soc_register_platform(&spi
->dev
, &rt5514_spi_platform
);
414 dev_err(&spi
->dev
, "Failed to register platform.\n");
418 ret
= devm_snd_soc_register_component(&spi
->dev
,
419 &rt5514_spi_dai_component
,
422 dev_err(&spi
->dev
, "Failed to register component.\n");
429 static const struct of_device_id rt5514_of_match
[] = {
430 { .compatible
= "realtek,rt5514", },
433 MODULE_DEVICE_TABLE(of
, rt5514_of_match
);
435 static struct spi_driver rt5514_spi_driver
= {
438 .of_match_table
= of_match_ptr(rt5514_of_match
),
440 .probe
= rt5514_spi_probe
,
442 module_spi_driver(rt5514_spi_driver
);
444 MODULE_DESCRIPTION("RT5514 SPI driver");
445 MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
446 MODULE_LICENSE("GPL v2");