aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/davinci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r--sound/soc/davinci/davinci-mcasp.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 35a6292889a5..93f2e294d649 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -48,6 +48,7 @@ struct davinci_mcasp {
48 u8 *serial_dir; 48 u8 *serial_dir;
49 u8 version; 49 u8 version;
50 u16 bclk_lrclk_ratio; 50 u16 bclk_lrclk_ratio;
51 int streams;
51 52
52 /* McASP FIFO related */ 53 /* McASP FIFO related */
53 u8 txnumevt; 54 u8 txnumevt;
@@ -110,10 +111,31 @@ static void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
110 printk(KERN_ERR "GBLCTL write error\n"); 111 printk(KERN_ERR "GBLCTL write error\n");
111} 112}
112 113
114static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
115{
116 u32 rxfmctl = mcasp_get_reg(mcasp->base + DAVINCI_MCASP_RXFMCTL_REG);
117 u32 aclkxctl = mcasp_get_reg(mcasp->base + DAVINCI_MCASP_ACLKXCTL_REG);
118
119 return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
120}
121
113static void mcasp_start_rx(struct davinci_mcasp *mcasp) 122static void mcasp_start_rx(struct davinci_mcasp *mcasp)
114{ 123{
115 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); 124 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
116 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); 125 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
126
127 /*
128 * When ASYNC == 0 the transmit and receive sections operate
129 * synchronously from the transmit clock and frame sync. We need to make
130 * sure that the TX signlas are enabled when starting reception.
131 */
132 if (mcasp_is_synchronous(mcasp)) {
133 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
134 TXHCLKRST);
135 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
136 TXCLKRST);
137 }
138
117 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); 139 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
118 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXBUF_REG, 0); 140 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXBUF_REG, 0);
119 141
@@ -123,6 +145,10 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
123 145
124 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); 146 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
125 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); 147 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
148
149 if (mcasp_is_synchronous(mcasp))
150 mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
151 TXFSRST);
126} 152}
127 153
128static void mcasp_start_tx(struct davinci_mcasp *mcasp) 154static void mcasp_start_tx(struct davinci_mcasp *mcasp)
@@ -158,6 +184,8 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
158{ 184{
159 u32 reg; 185 u32 reg;
160 186
187 mcasp->streams++;
188
161 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 189 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
162 if (mcasp->txnumevt) { /* enable FIFO */ 190 if (mcasp->txnumevt) { /* enable FIFO */
163 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 191 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
@@ -177,13 +205,29 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
177 205
178static void mcasp_stop_rx(struct davinci_mcasp *mcasp) 206static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
179{ 207{
208 /*
209 * In synchronous mode stop the TX clocks if no other stream is
210 * running
211 */
212 if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
213 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
214
180 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, 0); 215 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
181 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 216 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
182} 217}
183 218
184static void mcasp_stop_tx(struct davinci_mcasp *mcasp) 219static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
185{ 220{
186 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, 0); 221 u32 val = 0;
222
223 /*
224 * In synchronous mode keep TX clocks running if the capture stream is
225 * still running.
226 */
227 if (mcasp_is_synchronous(mcasp) && mcasp->streams)
228 val = TXHCLKRST | TXCLKRST | TXFSRST;
229
230 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, val);
187 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 231 mcasp_set_reg(mcasp->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
188} 232}
189 233
@@ -191,6 +235,8 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
191{ 235{
192 u32 reg; 236 u32 reg;
193 237
238 mcasp->streams--;
239
194 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 240 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
195 if (mcasp->txnumevt) { /* disable FIFO */ 241 if (mcasp->txnumevt) { /* disable FIFO */
196 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 242 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;