[Sound-open-firmware] [PATCH 01/15] [RFC][v2]DMIC: Add PDM microphones (DMIC) support to DAI

Seppo Ingalsuo seppo.ingalsuo at linux.intel.com
Mon May 7 16:38:56 CEST 2018



On 07.05.2018 14:37, Liam Girdwood wrote:
> On Fri, 2018-05-04 at 18:01 +0300, Seppo Ingalsuo wrote:
>> This patch adds the DMIC audio capture driver for SOF DAI component use.
>> The DMIC feature allows to directly attach one to (typically) four PDM
>> digital microphones into Intel SoC without a separate codec IC. This is
>> supported by APL and most successor platforms.
>>
>> Corresponding patches are needed for kernel driver and topology to enable
>> this feature.
>>
>> Tested in
>> APL UP squared board without connected microphones
>> SOF git master 3ad69eb715a09de9a0b91c56c9cca8a79ead00a9
>>
>> Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
>> ---
>>   src/drivers/dmic.c | 1383 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 1383 insertions(+)
>>   create mode 100644 src/drivers/dmic.c
>>
>>
> I've applied 2,5,7,8,9,10,11,14 and 15. The rest are good but needs

Great, it was RFC but no objections! It saves me a lot of effort for 
next patch version.

>   
>
>
>> +
>> +#if defined MODULE_TEST
>> +#include <stdio.h>
>> +#define QTOF(x, q) ((float)(x) / ((int64_t)1 << (q)))
>> +#endif
> Does this need to go in a maths header ?

Yep, it will be useful since the new platforms have float capability and 
there will be more float <-> fractional conversions needed when we have 
float pipelines support. Also, this is not optimized at all but can work 
as reference.


>
> +
> +#if DMIC_HW_VERSION == 1
> +       ipm_helper(&ipm, stereo, swap, dmic);
> +       val = OUTCONTROL0_TIE(0) |
> +               OUTCONTROL0_SIP(0) |
> +               OUTCONTROL0_FINIT(1) |
> +               OUTCONTROL0_FCI(0) |
> +               OUTCONTROL0_BFTH(bfth) |
> +               OUTCONTROL0_OF(of0) |
> +               OUTCONTROL0_IPM(ipm) |
> +               OUTCONTROL0_TH(th);
> +       dmic_write(dai, OUTCONTROL0, val);
> +       trace_value(val);
> +
> +       val = OUTCONTROL1_TIE(0) |
> +               OUTCONTROL1_SIP(0) |
> +               OUTCONTROL1_FINIT(1) |
> +               OUTCONTROL1_FCI(0) |
> +               OUTCONTROL1_BFTH(bfth) |
> +               OUTCONTROL1_OF(of1) |
> +               OUTCONTROL1_IPM(ipm) |
> +               OUTCONTROL1_TH(th);
> +       dmic_write(dai, OUTCONTROL1, val);
> +       trace_value(val);
> +#endif
> +
> +#if DMIC_HW_VERSION == 2
> +       source_ipm_helper(source, &ipm, stereo, swap, dmic);
>
>
> Best to use #elif
>
>
>
> +/* start the DMIC for capture */
> +static void dmic_start(struct dai *dai, int direction)
> +{
> +       struct dmic_pdata *dmic = dai_get_drvdata(dai);
> +       int i;
> +       int mic_a;
> +       int mic_b;
> +       int fir_a;
> +       int fir_b;
> +
> +       if (direction != DAI_DIR_CAPTURE)
> +               return;
> +
> +       /* enable port */
> +       spin_lock(&dmic->lock);
> +       trace_dmic("sta");
> +       dmic->state = COMP_STATE_ACTIVE;
>
>
> Regarding the spinlock, was this to be used to guarantee that both mic A and B
> would use a compatible configuration at start ?

I only copied the spinlock practice from SSP so not sure about need. 
Microphones A (left) and B (right) control for each PDM controller 
should be OK since the HW re-samples the signals to not mess up internal 
processing pipeline. Concerning FIFOs A and B this may not be sufficient.

I'd assume the code could work 1. capture via FIFO A. 2. stop capture, 
3. capture via FIFO B so no support for simultaneous or overlapping 
usage. Some next driver version should address that.

What is your proposal?

>   
>
>> +	if (direction != DAI_DIR_CAPTURE) {
>> +		trace_dmic_error("cap");
>> +		return -EINVAL;
>> +	}
>
> You need to do this here :-
>
> 	ret = comp_set_state(dev, cmd);
> 	if (ret < 0)
> 		return ret;
>
> This does all state checking/setting so no need to do it below.

OK.  Keyon is also is checking the same with SSP so I can follow how 
it's done for SSP.


>
>> +
>> +	switch (cmd) {
>> +	case COMP_TRIGGER_START:
>> +		if (dmic->state == COMP_STATE_PREPARE ||
>> +			dmic->state == COMP_STATE_PAUSED) {
>> +			dmic_start(dai, direction);
>> +		} else {
>> +			trace_dmic_error("cst");
>> +			trace_value(dmic->state);
>> +		}
>> +		break;
>> +	case COMP_TRIGGER_RELEASE:
>> +		if (dmic->state == COMP_STATE_PREPARE) {
>> +			dmic_start(dai, direction);
>> +		} else {
>> +			trace_dmic_error("crl");
>> +			trace_value(dmic->state);
>> +		}
>> +		break;
>> +	case COMP_TRIGGER_STOP:
>> +	case COMP_TRIGGER_PAUSE:
>> +		dmic->state = COMP_STATE_PAUSED;
>> +		dmic_stop(dai);
>> +		break;
>> +	case COMP_TRIGGER_RESUME:
>> +		dmic_context_restore(dai);
>> +		break;
>> +	case COMP_TRIGGER_SUSPEND:
>> +		dmic_context_store(dai);
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/* TODO: No idea what should be done here. Currently only trace the
>> + * status register that contains a few status and error bit fields.
>> + */
> The intention here is to emit any DMIC errors via trace errors to help with
> debug.

OK, sounds then just removing the TODO comment is enough. When I had DMA 
mis-programmed I saw these DMIC irq events.

Thanks,
Seppo


>
>> +static void dmic_irq_handler(void *data)
>> +{
>> +	struct dai *dai = data;
>> +	uint32_t val;
>> +
>> +	/* Trace OUTSTAT0 register */
>> +	val = dmic_read(dai, OUTSTAT0);
>> +	trace_dmic("irq");
>> +
>> +	if (val & OUTSTAT0_ROR_BIT)
>> +		trace_dmic_error("eor"); /* Full fifo or PDM overrrun */
>> +
>> +	trace_value(dmic_read(dai, OUTSTAT0));
>> +
>> +	/* clear IRQ */
>> +	platform_interrupt_clear(dmic_irq(dai), 1);
>> +}
>>
> Liam
> _______________________________________________
> Sound-open-firmware mailing list
> Sound-open-firmware at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
>



More information about the Sound-open-firmware mailing list