diff options
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 48 |
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 | ||
114 | static 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 | |||
113 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 122 | static 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 | ||
128 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 154 | static 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 | ||
178 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | 206 | static 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 | ||
184 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | 219 | static 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; |