@@ -34,8 +34,10 @@ struct rp1_aout {
3434 struct clk * clk ;
3535 struct dma_chan * chan ;
3636 int opened ;
37- spinlock_t count_lock ; /* protects the IRQ counter */
38- u32 counter ;
37+ spinlock_t pos_lock ; /* protects the following in ISR context */
38+ dma_cookie_t cookie ;
39+ snd_pcm_uframes_t pos_period ;
40+ snd_pcm_uframes_t pos_last ;
3941};
4042
4143static inline void aout_reg_wr (struct rp1_aout * ao , unsigned int offset , u32 val )
@@ -147,10 +149,10 @@ static const struct snd_pcm_hardware rp1_aout_hw = {
147149 .rates = SNDRV_PCM_RATE_48000 ,
148150 .rate_min = 48000 ,
149151 .rate_max = 48000 ,
150- .channels_min = 1 ,
152+ .channels_min = 2 ,
151153 .channels_max = 2 ,
152154 .buffer_bytes_max = 128 * 1024 ,
153- .period_bytes_min = 4 * 1024 ,
155+ .period_bytes_min = 1 * 1024 ,
154156 .period_bytes_max = 128 * 1024 ,
155157 .periods_min = 1 ,
156158 .periods_max = 16 ,
@@ -240,9 +242,10 @@ static void my_callback(void * arg)
240242 struct rp1_aout * aout = snd_pcm_substream_chip (substream );
241243 unsigned long flags ;
242244
243- spin_lock_irqsave (& aout -> count_lock , flags );
244- aout -> counter ++ ;
245- spin_unlock_irqrestore (& aout -> count_lock , flags );
245+ spin_lock_irqsave (& aout -> pos_lock , flags );
246+ aout -> pos_period += substream -> runtime -> period_size ;
247+ spin_unlock_irqrestore (& aout -> pos_lock , flags );
248+
246249 snd_pcm_period_elapsed (substream );
247250 }
248251}
@@ -258,14 +261,14 @@ static int rp1_aout_prepare(struct snd_pcm_substream *substream)
258261
259262 memset (& config , 0 , sizeof (config ));
260263 config .direction = DMA_MEM_TO_DEV ;
261- config .dst_addr_width = ( runtime -> channels < 2 ) ? DMA_SLAVE_BUSWIDTH_2_BYTES : DMA_SLAVE_BUSWIDTH_4_BYTES ;
264+ config .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
262265 config .dst_addr = aout -> physaddr + AUDIO_OUT_SAMPLE_FIFO_OFFSET ;
263266 config .dst_maxburst = 4 ;
264267 config .device_fc = false;
265268 ret = dmaengine_slave_config (aout -> chan , & config );
266269 desc = dmaengine_prep_dma_cyclic (aout -> chan , runtime -> dma_addr ,
267- runtime -> buffer_size * 2 * runtime -> channels ,
268- runtime -> period_size * 2 * runtime -> channels ,
270+ frames_to_bytes ( runtime , runtime -> buffer_size ) ,
271+ frames_to_bytes ( runtime , runtime -> period_size ) ,
269272 DMA_MEM_TO_DEV ,
270273 DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_PREP_FENCE );
271274 if (!desc ) {
@@ -275,9 +278,11 @@ static int rp1_aout_prepare(struct snd_pcm_substream *substream)
275278 desc -> callback = my_callback ;
276279 desc -> callback_param = substream ;
277280 ret = dmaengine_submit (desc );
278- spin_lock_irqsave (& aout -> count_lock , flags );
279- aout -> counter = 0 ;
280- spin_unlock_irqrestore (& aout -> count_lock , flags );
281+ spin_lock_irqsave (& aout -> pos_lock , flags );
282+ aout -> cookie = ret ;
283+ aout -> pos_period = 0 ;
284+ aout -> pos_last = 0 ;
285+ spin_unlock_irqrestore (& aout -> pos_lock , flags );
281286
282287 return (ret < 0 ) ? ret : 0 ;
283288}
@@ -305,13 +310,31 @@ static snd_pcm_uframes_t rp1_aout_pointer(struct snd_pcm_substream *substream)
305310{
306311 struct rp1_aout * aout = snd_pcm_substream_chip (substream );
307312 unsigned long flags ;
308- unsigned long samp ;
313+ struct dma_tx_state state ;
314+ snd_pcm_uframes_t pos ;
315+ enum dma_status st ;
316+
317+ spin_lock_irqsave (& aout -> pos_lock , flags );
318+ st = dmaengine_tx_status (aout -> chan , aout -> cookie , & state );
319+ pos = aout -> pos_period ;
320+ if (st == DMA_IN_PROGRESS ) {
321+ snd_pcm_uframes_t u ;
322+
323+ u = bytes_to_frames (substream -> runtime , state .residue );
324+ u %= substream -> runtime -> period_size ;
325+ if (u )
326+ pos += substream -> runtime -> period_size - u ;
327+ }
328+ if (pos < aout -> pos_last )
329+ pos += substream -> runtime -> period_size ;
330+ if (aout -> pos_period >= substream -> runtime -> buffer_size ) {
331+ aout -> pos_period -= substream -> runtime -> buffer_size ;
332+ pos -= substream -> runtime -> buffer_size ;
333+ }
334+ aout -> pos_last = pos ;
335+ spin_unlock_irqrestore (& aout -> pos_lock , flags );
309336
310- spin_lock_irqsave (& aout -> count_lock , flags );
311- samp = aout -> counter ;
312- spin_unlock_irqrestore (& aout -> count_lock , flags );
313- samp = (samp * substream -> runtime -> period_size ) % substream -> runtime -> buffer_size ;
314- return samp ;
337+ return pos % substream -> runtime -> buffer_size ;
315338}
316339
317340static struct snd_pcm_ops rp1_aout_ops = {
@@ -352,7 +375,7 @@ static int rp1_aout_platform_probe(struct platform_device *pdev)
352375 "could not request DMA channel\n" );
353376
354377
355- spin_lock_init (& aout -> count_lock );
378+ spin_lock_init (& aout -> pos_lock );
356379 aout -> dev = & pdev -> dev ;
357380 dev_set_drvdata (& pdev -> dev , aout );
358381
0 commit comments