Skip to content

Commit ba43740

Browse files
sound: soc: rp1: Disable mono; fix pointer reporting. TO SQUASH.
- Remove mono support (as I wasn't convinced it worked correctly). - Reduce minimum period size from 4096 to 1024 bytes (256 samples). - Fix pointer reporting using DMA residue, but don't fully trust it! Fall back on period count when residue % period == 0, and fix up period boundary cases to avoid time going backwards.
1 parent aec0c90 commit ba43740

File tree

1 file changed

+43
-20
lines changed

1 file changed

+43
-20
lines changed

sound/soc/rp1/rp1-aout.c

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

4143
static 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

317340
static 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

Comments
 (0)