[Sound-open-firmware] [PATCH 1/4] [RFC]DMIC: Add PDM microphones (DMIC) support to DAI
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Wed May 2 15:43:54 CEST 2018
>>> + /* Loop possible clock dividers and check based on resulting
>>> + * oversampling ratio that CIC and FIR decimation ratios are
>>> + * feasible. The ratios need to be integers. Also the mic clock
>>> + * duty cycle need to be within limits.
>>> + */
>>> + for (clkdiv = clkdiv_min; clkdiv <= clkdiv_max; clkdiv++) {
>>> + c1 = clkdiv >> 1;
>>> + c2 = clkdiv - c1;
>>> + du_min = 100 * c1 / clkdiv;
>>
>> du_min = 100 * (clkdiv/2)/clkdiv -> 50?
>>
>>> + du_max = 100 * c2 / clkdiv;
>>
>> c2 = clkdiv - c1 = clkdiv/2, so du_min == du_max ?
>> what am I missing?
>
> The duty cycle becomes non-50% when the divider is odd, e.g. clkdiv = 5
> case:
>
> c1 = clkdiv >> 1 = 2
> c2 = clkdiv - c1 = 5 - 2 = 3
> du_min = 100*c1/clkdiv = 100*2/5 = 200/5 = 40
> du_max = 100*c2/clkdif = 100*3/5 = 300/5 = 60
>
> The latter equation can be though simplified to "c2 = 100 - c1;" that I
> didn't realize earlier.
And you may want to add a comment that the ratio is not 50% for odd
dividers, I missed the non-linear result.
>>> + /* Check for request only for FIFO A or B. In such case pass
>>> list for
>>> + * A or B as such.
>>> + */
>>> + if (b->num_of_modes == 0) {
>>> + c->num_of_modes = a->num_of_modes;
>>> + for (i = 0; i < a->num_of_modes; i++) {
>>> + c->clkdiv[i] = a->clkdiv[i];
>>> + c->mcic[i] = a->mcic[i];
>>> + c->mfir_a[i] = a->mfir[i];
>>> + c->mfir_b[i] = 0;
>>
>> is this initialization to zero needed?
>
> Yes, It indicates the FIFO B path won't be used.
yes, but you are only using the first element as an indication. you want
to add a comment here to help the reader follow the flow.
>
>>
>>> + }
>>> + return;
>>> + }
>>> +
>>> + if (a->num_of_modes == 0) {
>>> + c->num_of_modes = b->num_of_modes;
>>> + for (i = 0; i < b->num_of_modes; i++) {
>>> + c->clkdiv[i] = b->clkdiv[i];
>>> + c->mcic[i] = b->mcic[i];
>>> + c->mfir_b[i] = b->mfir[i];
>>> + c->mfir_a[i] = 0;
>>
>> same here, is this initialization needed?
>
> And vice versa no FIFO A path used.
same here.
>>> +
>>> + shift = 0;
>>> + while ((new_scale << shift) < (1 << 20))
>>> + shift++;
>>
>> don't we have some sort of macro for this (find number of leading
>> zeroes)?
>
> Not yet I think but such would be useful. I'll add it to math/numbers.
> Since DSPs have an instruction for that it would be then easier to
> optimize into single location.
ok
>>> + /* Calculate CIC shift from the decimation factor specific gain.
>>> + */
>>> + mcic = cfg->mcic;
>>> + g_cic = mcic * mcic * mcic * mcic * mcic;
>>
>> yikes, what is this mcic^5 ?
>
> Yep, it's the gain for +1 / -1 PDM bits in CIC decimator part. It's
> needed to set the scaling HW shifter. It also gives some idea of
> oversampling ratios to use for a microphone to get some # of bits of
> resolution as PCM code.
I meant: where does this ^5 come from? First time i see this sort of
formula in filter design.
>>> + for (i = 0; i < dmic->number_of_pdm_controllers; i++) {
>>> + if (dmic->pdm[i].enable_mic_a > 0 ||
>>> + dmic->pdm[i].enable_mic_b > 0)
>>> + pdm[i] = 1;
>>> + else
>>> + pdm[i] = 0;
>>> +
>>> + if (dmic->pdm[i].enable_mic_a > 0 &&
>>> + dmic->pdm[i].enable_mic_b > 0) {
>>> + stereo[i] = 1;
>>> + swap[i] = 0;
>>> + } else {
>>> + stereo[i] = 0;
>>> + if (dmic->pdm[i].enable_mic_a == 0)
>>> + swap[i] = 1;
>>> + else
>>> + swap[i] = 0;
>>> + }
>>
>> the logic is weird here.
>>
>> if (a || b)
>> ...
>> else
>> ...
>>
>> if (a && b)
>> ...
>> else
>> // this could be a || b or !a && !b??
>
> I'm not sure this if spaghetti can be simplified. If the PDM bits
> processing is not stereo the mono-left mic (a) HW mode is used. If the
> the right mic (b) needs to be used as mono input then need to swap the
> PDM bit inputs to process it as mono-left.
>
> The FIFO packer packer has a mono mode so the use or left channel
> processing for right microphone is only a HW internal thing.
may something like:
cnt=0;
for (i = 0; i < dmic->number_of_pdm_controllers; i++) {
if (dmic->pdm[i].enable_mic_a > 0)
cnt++;
if (dmic->pdm[i].enable_mic_b > 0)
cnt++;
pdm[i] = !!cnt;
cnt >>= 1;
stereo[i] = cnt;
swap[i] = dmic->pdm[i].enable_mic_b & !cnt;
}
>>> + /* Mono right channel mic usage requires swap of PDM channels
>>> + * since the mono decimation is done with only left channel
>>> + * processing active.
>>> + */
>>> + edge = dmic->pdm[i].clk_edge;
>>> + if (swap[i])
>>> + edge = edge ^ 1;
>>
>> ! edge?
>
> If C standard has it defined that !0 gives 1 and !1 gives 0 it's OK to
> change. I used bitwise XOR to make it sure.
yes, that's ok. The xor is not usually not used for this.
>>> +static int dmic_trigger(struct dai *dai, int cmd, int direction)
>>> +{
>>> + struct dmic_pdata *dmic = dai_get_drvdata(dai);
>>> +
>>> + trace_dmic("tri");
>>> +
>>> + /* dai private is set in dmic_probe(), error if not set */
>>> + if (!dmic) {
>>> + trace_dmic_error("trn");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + if (direction != DAI_DIR_CAPTURE) {
>>> + trace_dmic_error("cap");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + 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);
>>
>> shouldn't the state assignment be protected by a spinlock (as done for
>> the start case)?
>> Also is this really PAUSED?
>
> I followed in this part the ssp driver. I have no plans to implement
> anything like RAM buffer for recording pause so I don't know what should
> be done with it. Could COMP_TRIGGER_PAUSE be removed and return error if
> attempted?
Liam or Keyon, can you look at this? The spinlock usage is odd and I
can't remember why we would use PAUSE even for SSP.
More information about the Sound-open-firmware
mailing list