aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/sirf/Kconfig6
-rw-r--r--sound/soc/sirf/Makefile2
-rw-r--r--sound/soc/sirf/sirf-usp.c415
-rw-r--r--sound/soc/sirf/sirf-usp.h293
4 files changed, 716 insertions, 0 deletions
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index 89e89429b04a..840058dcad09 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -12,3 +12,9 @@ config SND_SOC_SIRF_AUDIO
12config SND_SOC_SIRF_AUDIO_PORT 12config SND_SOC_SIRF_AUDIO_PORT
13 select REGMAP_MMIO 13 select REGMAP_MMIO
14 tristate 14 tristate
15
16config SND_SOC_SIRF_USP
17 tristate "SoC Audio (I2S protocol) for SiRF SoC USP interface"
18 depends on SND_SOC_SIRF
19 select REGMAP_MMIO
20 tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index 913b93231d4e..dd917f20f12f 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,5 +1,7 @@
1snd-soc-sirf-audio-objs := sirf-audio.o 1snd-soc-sirf-audio-objs := sirf-audio.o
2snd-soc-sirf-audio-port-objs := sirf-audio-port.o 2snd-soc-sirf-audio-port-objs := sirf-audio-port.o
3snd-soc-sirf-usp-objs := sirf-usp.o
3 4
4obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o 5obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
5obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o 6obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
7obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
new file mode 100644
index 000000000000..bdf6aae3e6d0
--- /dev/null
+++ b/sound/soc/sirf/sirf-usp.c
@@ -0,0 +1,415 @@
1/*
2 * SiRF USP in I2S/DSP mode
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8#include <linux/module.h>
9#include <linux/io.h>
10#include <linux/of.h>
11#include <linux/clk.h>
12#include <linux/pm_runtime.h>
13#include <sound/soc.h>
14#include <sound/pcm_params.h>
15#include <sound/dmaengine_pcm.h>
16
17#include "sirf-usp.h"
18
19struct sirf_usp {
20 struct regmap *regmap;
21 struct clk *clk;
22 u32 mode1_reg;
23 u32 mode2_reg;
24 int daifmt_format;
25 struct snd_dmaengine_dai_dma_data playback_dma_data;
26 struct snd_dmaengine_dai_dma_data capture_dma_data;
27};
28
29static void sirf_usp_tx_enable(struct sirf_usp *usp)
30{
31 regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
32 USP_TX_FIFO_RESET, USP_TX_FIFO_RESET);
33 regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
34
35 regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
36 USP_TX_FIFO_START, USP_TX_FIFO_START);
37
38 regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
39 USP_TX_ENA, USP_TX_ENA);
40}
41
42static void sirf_usp_tx_disable(struct sirf_usp *usp)
43{
44 regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
45 USP_TX_ENA, ~USP_TX_ENA);
46 /* FIFO stop */
47 regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
48}
49
50static void sirf_usp_rx_enable(struct sirf_usp *usp)
51{
52 regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
53 USP_RX_FIFO_RESET, USP_RX_FIFO_RESET);
54 regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
55
56 regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
57 USP_RX_FIFO_START, USP_RX_FIFO_START);
58
59 regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
60 USP_RX_ENA, USP_RX_ENA);
61}
62
63static void sirf_usp_rx_disable(struct sirf_usp *usp)
64{
65 regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
66 USP_RX_ENA, ~USP_RX_ENA);
67 /* FIFO stop */
68 regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
69}
70
71static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
72{
73 struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
74 snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data,
75 &usp->capture_dma_data);
76 return 0;
77}
78
79static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
80 unsigned int fmt)
81{
82 struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
83
84 /* set master/slave audio interface */
85 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
86 case SND_SOC_DAIFMT_CBM_CFM:
87 break;
88 default:
89 dev_err(dai->dev, "Only CBM and CFM supported\n");
90 return -EINVAL;
91 }
92
93 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
94 case SND_SOC_DAIFMT_I2S:
95 case SND_SOC_DAIFMT_DSP_A:
96 usp->daifmt_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
97 break;
98 default:
99 dev_err(dai->dev, "Only I2S and DSP_A format supported\n");
100 return -EINVAL;
101 }
102
103 return 0;
104}
105
106static int sirf_usp_i2s_startup(struct snd_pcm_substream *substream,
107 struct snd_soc_dai *dai)
108{
109 struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
110
111 /* Configure RISC mode */
112 regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE,
113 USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL);
114
115 /*
116 * Configure DMA IO Length register
117 * Set no limit, USP can receive data continuously until it is diabled
118 */
119 regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0);
120 regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0);
121
122 regmap_write(usp->regmap, USP_RX_FRAME_CTRL, USP_SINGLE_SYNC_MODE);
123
124 regmap_write(usp->regmap, USP_TX_FRAME_CTRL, USP_TXC_SLAVE_CLK_SAMPLE);
125
126 /* Configure Mode2 register */
127 regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) |
128 (0 << USP_TXD_DELAY_LEN_OFFSET));
129
130 /* Configure Mode1 register */
131 regmap_write(usp->regmap, USP_MODE1,
132 USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING |
133 USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 |
134 USP_TX_UFLOW_REPEAT_ZERO);
135
136 /* Configure RX DMA IO Control register */
137 regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0);
138
139 /* Congiure RX FIFO Control register */
140 regmap_write(usp->regmap, USP_RX_FIFO_CTRL,
141 (USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) |
142 (USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET));
143
144 /* Congiure RX FIFO Level Check register */
145 regmap_write(usp->regmap, USP_RX_FIFO_LEVEL_CHK,
146 RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B));
147
148 /* Configure TX DMA IO Control register*/
149 regmap_write(usp->regmap, USP_TX_DMA_IO_CTRL, 0);
150
151 /* Configure TX FIFO Control register */
152 regmap_write(usp->regmap, USP_TX_FIFO_CTRL,
153 (USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) |
154 (USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET));
155 /* Congiure TX FIFO Level Check register */
156 regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK,
157 TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04));
158
159 return 0;
160}
161
162static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
163 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
164{
165 struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
166 u32 data_len, frame_len, shifter_len;
167
168 switch (params_format(params)) {
169 case SNDRV_PCM_FORMAT_S16_LE:
170 data_len = 16;
171 frame_len = 16;
172 break;
173 case SNDRV_PCM_FORMAT_S24_LE:
174 data_len = 24;
175 frame_len = 32;
176 break;
177 case SNDRV_PCM_FORMAT_S24_3LE:
178 data_len = 24;
179 frame_len = 24;
180 break;
181 default:
182 dev_err(dai->dev, "Format unsupported\n");
183 return -EINVAL;
184 }
185
186 shifter_len = data_len;
187
188 switch (usp->daifmt_format) {
189 case SND_SOC_DAIFMT_I2S:
190 regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
191 USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);