diff mbox

omap4-droid4: voice call support was Re: [PATCHv5, 5/5] ARM: dts: omap4-droid4: add soundcard

Message ID 20180329014507.GM5700@atomide.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tony Lindgren March 29, 2018, 1:45 a.m. UTC
Hi,

* Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180328 14:03]:
> Hi,
> 
> On Wed, Mar 28, 2018 at 10:29:10AM +0800, Mark Brown wrote:
> > On Wed, Mar 28, 2018 at 12:22:37AM +0200, Sebastian Reichel wrote:
> > > On Tue, Mar 27, 2018 at 08:14:41PM +0800, Mark Brown wrote:
> > 
> > > > No, this is exactly the sort of use case with multiple DAIs that the
> > > > graph card is intended to enable over the old simple-card.
> > 
> > > +----------+         +-------------+
> > > | OMAP4    |         | CPCAP       |
> > > |          |         |             |
> > > | [McBSP2] | <-----> | [HiFi DAI]  |
> > > |          |         |             |
> > > | [McBSP3] | <--+--> | [Voice DAI] |
> > > |          |    |    |             |
> > > +----------+    |    +-------------+
> > >                 |
> > > +----------+    |    +-------------+
> > > | MDM6600  |    |    | WL1285      |
> > > |          |    |    |             |
> > > |    [DAI] | <--+--> | [DAI]       |
> > > |          |         |             |
> > > +----------+         +-------------+
> > 
> > > Legend:
> > >     OMAP4   = SoC running Linux
> > >     CPCAP   = Audio codec
> > >     MDM6600 = Baseband
> > >     WL1285  = Bluetooth
> > 
> > > Re-reading the audio-graph-card binding document I still don't see
> > > how the network (OMAP.McBSP3, CPCAP.Voice, MDM6600, WL1285) is
> > > supposed to look like. It seems to expect point-to-point DAI
> > > connections.
> > 
> > Ugh, a TDM mux?
> 
> Yes, at least that's how I understood Motorola's code.

Hmm is there some active component doing the muxing then?
Maybe the "AT+CMUT=0" part below?

> > That's really unusual and not particularly supported yet, you'd
> > need to extend the graph card to do it.  It's where things should
> > end up for a generic card though.
> 
> Motorola's driver provided the following modes:
> 
> OMAP4 <-> CPCAP      (voice recording)
> MDM6600 <-> CPCAP    (voice call, CPU not involved)
> OMAP4 <-> WL1285     (bluetooth HFP/HSP)
> MDM6600 <-> WL1285   (bluetooth voice call)
> 
> In case of the last two variants, the bus clock is provided by
> CPCAP, so it needs to be enabled for any audio stream. I suppose
> the codec <-> codec as part of TDM is out of scope for the graph
> card and we need a Droid 4 specific card driver?

Hmm well I got audio call hacked to work as a proof of concept hack,
see below. Maybe it can be used to verify some of the assumptions
above.

Then.. To split the work a bit, can you guys maybe try to decode
the cpcap register values and try to do a proper ASoC driver patch?

Meanwhile, I can try to make voice calls more reproducable with
qmi or MM for example instead of just n_gsm.. And then I'll try
to fix my n_gsm pile of hacks for posting..

Cheers,

Tony

8< --------------------------
From tony Mon Sep 17 00:00:00 2001
From: Tony Lindgren <tony@atomide.com>
Date: Wed, 28 Mar 2018 08:29:38 -0700
Subject: [PATCH] NOT FOR MERGING: Quick hack for droid 4 mdm6600 voice
 call

Here's quick hack to allow making a voice call on mdm6600 based on
diffing the cpcap registers in Android. The patch just keeps overwriting
the cpcap values every second so it's nowhere near usable for merging,
just a test patch.

Looks like the cpcap register changes during a speaker phone audio call are:

@@ -510,17 +510,17 @@
 07f4: 0000
 07f8: 0000
 07fc: 0000
-0800: 0065
-0804: 0000
-0808: 0040
+0800: 0025     # CPCAP_REG_VAUDIOC     VAUDIO Control
+0804: 60cf     # CPCAP_REG_CC          Codec Control, moto cpcap.c:1337 sets 0x0093?
+0808: ae0a     # CPCAP_REG_CDI         Codec Digital Interface
 080c: 0000
 0810: 0004
-0814: 0804
-0818: 079c
-081c: 0000
-0820: 0924
-0824: 0000
-0828: 0000
+0814: 0cc0     # CPCAP_REG_TXI         TX Inputs, moto cpcap.c:1340 sets 0x0CC6?
+0818: 0610     # CPCAP_REG_TXMP        TX MIC PGA's, moto cpcap.c:1343 sets 0x0273?
+081c: 0006     # CPCAP_REG_RXOA        RX Output Amplifiers
+0820: 0b2c     # CPCAP_REG_RXVC        RX Volume Control
+0824: 0606     # CPCAP_REG_RXCOA       RX Codec to Output Amps
+0828: 0600     # CPCAP_REG_RXSDOA      RX Stereo DAC to Output Amps
 082c: 0400
 0830: 0000
 0834: 0030

I wonder if mdm6600 is the i2s master during the voice call?

Then using the n_gsm ts 27.010 uart mux, I dial:

./ngsm-rw 1 "AT+CFUN=1"		# connect to network
U0001+CFUN:OK
./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
U0001+CMUT:OK
./ngsm-rw 1 "ATD#123"		# dial number
U0001D:OK

And I do hear a voice talking over the speakerphone :) Sorry have not tested the
mic yet..

FYI, the ngsm-rw script I use is just:

#!/bin/sh

if [ "${1}" == "" ]; then
        echo "Usage: $0 port command"
        exit 1
fi

port=${1}
command=${2}

exec 3<>/dev/gsmtty${port}
printf "U0001%s\r\0" ${command} >&3
read result <&3
exec 3>&-
exec 3<&-

echo ${result}

My n_gsm patches are not quite ready yet sorry.. But meanwhile hopefully this
can be somehow also done using qmi. At least "AT+CMUT=0" fails over ttyUSB4.
---
 sound/soc/codecs/cpcap.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

Comments

Sebastian Reichel March 29, 2018, 1:36 p.m. UTC | #1
Hi,

On Wed, Mar 28, 2018 at 06:45:07PM -0700, Tony Lindgren wrote:
> Hi,
> 
> * Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180328 14:03]:
> > Hi,
> > 
> > On Wed, Mar 28, 2018 at 10:29:10AM +0800, Mark Brown wrote:
> > > On Wed, Mar 28, 2018 at 12:22:37AM +0200, Sebastian Reichel wrote:
> > > > On Tue, Mar 27, 2018 at 08:14:41PM +0800, Mark Brown wrote:
> > > 
> > > > > No, this is exactly the sort of use case with multiple DAIs that the
> > > > > graph card is intended to enable over the old simple-card.
> > > 
> > > > +----------+         +-------------+
> > > > | OMAP4    |         | CPCAP       |
> > > > |          |         |             |
> > > > | [McBSP2] | <-----> | [HiFi DAI]  |
> > > > |          |         |             |
> > > > | [McBSP3] | <--+--> | [Voice DAI] |
> > > > |          |    |    |             |
> > > > +----------+    |    +-------------+
> > > >                 |
> > > > +----------+    |    +-------------+
> > > > | MDM6600  |    |    | WL1285      |
> > > > |          |    |    |             |
> > > > |    [DAI] | <--+--> | [DAI]       |
> > > > |          |         |             |
> > > > +----------+         +-------------+
> > > 
> > > > Legend:
> > > >     OMAP4   = SoC running Linux
> > > >     CPCAP   = Audio codec
> > > >     MDM6600 = Baseband
> > > >     WL1285  = Bluetooth
> > > 
> > > > Re-reading the audio-graph-card binding document I still don't see
> > > > how the network (OMAP.McBSP3, CPCAP.Voice, MDM6600, WL1285) is
> > > > supposed to look like. It seems to expect point-to-point DAI
> > > > connections.
> > > 
> > > Ugh, a TDM mux?
> > 
> > Yes, at least that's how I understood Motorola's code.
> 
> Hmm is there some active component doing the muxing then?
> Maybe the "AT+CMUT=0" part below?

I don't think, that there is a special hardware mux. I think each
device is configured to use a proper timeslot and/or is being used
exclusively.

> > > That's really unusual and not particularly supported yet, you'd
> > > need to extend the graph card to do it.  It's where things should
> > > end up for a generic card though.
> > 
> > Motorola's driver provided the following modes:
> > 
> > OMAP4 <-> CPCAP      (voice recording)
> > MDM6600 <-> CPCAP    (voice call, CPU not involved)
> > OMAP4 <-> WL1285     (bluetooth HFP/HSP)
> > MDM6600 <-> WL1285   (bluetooth voice call)
> > 
> > In case of the last two variants, the bus clock is provided by
> > CPCAP, so it needs to be enabled for any audio stream. I suppose
> > the codec <-> codec as part of TDM is out of scope for the graph
> > card and we need a Droid 4 specific card driver?
> 
> Hmm well I got audio call hacked to work as a proof of concept hack,
> see below. Maybe it can be used to verify some of the assumptions
> above.

Your proof of concept verifies the assumption, that the modem is
connected to the CPCAP voice DAI. This patchset is a proof, that the
voice DAI is connected to OMAP. So we can tell for sure, that this
is not a common direct DAI-to-DAI connection.

> Then.. To split the work a bit, can you guys maybe try to decode
> the cpcap register values and try to do a proper ASoC driver patch?
>
> Meanwhile, I can try to make voice calls more reproducable with
> qmi or MM for example instead of just n_gsm.. And then I'll try
> to fix my n_gsm pile of hacks for posting..
> 
> Cheers,
> 
> Tony
> 
> 8< --------------------------
> From tony Mon Sep 17 00:00:00 2001
> From: Tony Lindgren <tony@atomide.com>
> Date: Wed, 28 Mar 2018 08:29:38 -0700
> Subject: [PATCH] NOT FOR MERGING: Quick hack for droid 4 mdm6600 voice
>  call
> 
> Here's quick hack to allow making a voice call on mdm6600 based on
> diffing the cpcap registers in Android. The patch just keeps overwriting
> the cpcap values every second so it's nowhere near usable for merging,
> just a test patch.
> 
> Looks like the cpcap register changes during a speaker phone audio call are:
> 
> @@ -510,17 +510,17 @@
>  07f4: 0000
>  07f8: 0000
>  07fc: 0000
> -0800: 0065
> -0804: 0000
> -0808: 0040
> +0800: 0025     # CPCAP_REG_VAUDIOC     VAUDIO Control

enable vaudio (obviously required :))

> +0804: 60cf     # CPCAP_REG_CC          Codec Control, moto cpcap.c:1337 sets 0x0093?

0x6000 => clkfreq=19200000

The following bits are automatically set via DAPM by cpcap codec,
once it is used:

0x00c0 => "ADC Left" + "DAC Voice"
0x000f => "Highpass Filter TX" + "Highpass Filter RX"

> +0808: ae0a     # CPCAP_REG_CDI         Codec Digital Interface

0xa000 => enable PLL & use clock 1

This should be used by default for VOICE DAI.

0x0e00 => "Voice DAI Clock"=1 (handled by DAPM) , mode=I2S
0x000a => CPCAP_BIT_CLK_INV | CPCAP_BIT_MIC1_RX_TIMESLOT0

>  080c: 0000
>  0810: 0004
> -0814: 0804
> -0818: 079c
> -081c: 0000
> -0820: 0924
> -0824: 0000
> -0828: 0000
> +0814: 0cc0     # CPCAP_REG_TXI         TX Inputs, moto cpcap.c:1340 sets 0x0CC6?
> +0818: 0610     # CPCAP_REG_TXMP        TX MIC PGA's, moto cpcap.c:1343 sets 0x0273?
> +081c: 0006     # CPCAP_REG_RXOA        RX Output Amplifiers
> +0820: 0b2c     # CPCAP_REG_RXVC        RX Volume Control
> +0824: 0606     # CPCAP_REG_RXCOA       RX Codec to Output Amps
> +0828: 0600     # CPCAP_REG_RXSDOA      RX Stereo DAC to Output Amps

This configures the loudspeaker, mics and volume and enables the
required clocks/DACs/... This is already covered by the cpcap codec
driver. You just need to configure everything correctly in
alsamixer.

>  082c: 0400
>  0830: 0000
>  0834: 0030
> 
> I wonder if mdm6600 is the i2s master during the voice call?

I think cpcap is always the clock and frame master, but I think
mdm6600 is the remote side and OMAP is not involved at all.

-- Sebastian

> Then using the n_gsm ts 27.010 uart mux, I dial:
> 
> ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> U0001+CFUN:OK
> ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> U0001+CMUT:OK
> ./ngsm-rw 1 "ATD#123"		# dial number
> U0001D:OK
> 
> And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> mic yet..
> 
> FYI, the ngsm-rw script I use is just:
> 
> #!/bin/sh
> 
> if [ "${1}" == "" ]; then
>         echo "Usage: $0 port command"
>         exit 1
> fi
> 
> port=${1}
> command=${2}
> 
> exec 3<>/dev/gsmtty${port}
> printf "U0001%s\r\0" ${command} >&3
> read result <&3
> exec 3>&-
> exec 3<&-
> 
> echo ${result}
> 
> My n_gsm patches are not quite ready yet sorry.. But meanwhile hopefully this
> can be somehow also done using qmi. At least "AT+CMUT=0" fails over ttyUSB4.
> ---
>  sound/soc/codecs/cpcap.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 69 insertions(+), 1 deletion(-)
> 
> diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
> --- a/sound/soc/codecs/cpcap.c
> +++ b/sound/soc/codecs/cpcap.c
> @@ -251,6 +251,8 @@ struct cpcap_audio {
>  	int codec_clk_id;
>  	int codec_freq;
>  	int codec_format;
> +
> +	struct delayed_work work;
>  };
>  
>  static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
> @@ -1500,6 +1502,57 @@ static int cpcap_audio_reset(struct snd_soc_component *component,
>  	return 0;
>  }
>  
> +static void cpcap_soc_work(struct work_struct *work)
> +{
> +	struct cpcap_audio *cpcap = container_of(work,
> +						 struct cpcap_audio,
> +						 work.work);
> +	struct device *dev = cpcap->component->dev;
> +	int error;
> +
> +	dev_info(dev, "Somebody do a proper driver please %s\n", __func__);
> +
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
> +				   0xffff, 0x0025);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
> +				   0xffff, 0x60cf);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
> +				   0xffff, 0xae0a);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
> +				   0xffff, 0x0cc0);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXMP,
> +				   0xffff, 0x0610);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
> +				   0xffff, 0x0006);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXVC,
> +				   0xffff, 0x0b2c);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
> +				   0xffff, 0x0606);
> +	if (error)
> +		goto out;
> +	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
> +				   0xffff, 0x0600);
> +	if (error)
> +		goto out;
> +
> +out:
> +	schedule_delayed_work(&cpcap->work, msecs_to_jiffies(1000));
> +}
> +
>  static int cpcap_soc_probe(struct snd_soc_component *component)
>  {
>  	struct cpcap_audio *cpcap;
> @@ -1520,11 +1573,26 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
>  	if (err)
>  		return err;
>  
> -	return cpcap_audio_reset(component, false);
> +	err = cpcap_audio_reset(component, false);
> +	if (err)
> +		return err;
> +
> +	INIT_DELAYED_WORK(&cpcap->work, cpcap_soc_work);
> +	schedule_delayed_work(&cpcap->work, msecs_to_jiffies(1000));
> +
> +	return 0;
> +}
> +
> +static void cpcap_soc_remove(struct snd_soc_component *component)
> +{
> +	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
> +
> +	cancel_delayed_work_sync(&cpcap->work);
>  }
>  
>  static struct snd_soc_component_driver soc_codec_dev_cpcap = {
>  	.probe			= cpcap_soc_probe,
> +	.remove			= cpcap_soc_remove,
>  	.controls		= cpcap_snd_controls,
>  	.num_controls		= ARRAY_SIZE(cpcap_snd_controls),
>  	.dapm_widgets		= cpcap_dapm_widgets,
> -- 
> 2.16.3
Tony Lindgren March 29, 2018, 1:59 p.m. UTC | #2
* Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180329 13:37]:
> Hi,
> 
> On Wed, Mar 28, 2018 at 06:45:07PM -0700, Tony Lindgren wrote:
> > Hi,
> > 
> > * Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180328 14:03]:
> > > Hi,
> > > 
> > > On Wed, Mar 28, 2018 at 10:29:10AM +0800, Mark Brown wrote:
> > > > On Wed, Mar 28, 2018 at 12:22:37AM +0200, Sebastian Reichel wrote:
> > > > > On Tue, Mar 27, 2018 at 08:14:41PM +0800, Mark Brown wrote:
> > > > 
> > > > > > No, this is exactly the sort of use case with multiple DAIs that the
> > > > > > graph card is intended to enable over the old simple-card.
> > > > 
> > > > > +----------+         +-------------+
> > > > > | OMAP4    |         | CPCAP       |
> > > > > |          |         |             |
> > > > > | [McBSP2] | <-----> | [HiFi DAI]  |
> > > > > |          |         |             |
> > > > > | [McBSP3] | <--+--> | [Voice DAI] |
> > > > > |          |    |    |             |
> > > > > +----------+    |    +-------------+
> > > > >                 |
> > > > > +----------+    |    +-------------+
> > > > > | MDM6600  |    |    | WL1285      |
> > > > > |          |    |    |             |
> > > > > |    [DAI] | <--+--> | [DAI]       |
> > > > > |          |         |             |
> > > > > +----------+         +-------------+
> > > > 
> > > > > Legend:
> > > > >     OMAP4   = SoC running Linux
> > > > >     CPCAP   = Audio codec
> > > > >     MDM6600 = Baseband
> > > > >     WL1285  = Bluetooth
> > > > 
> > > > > Re-reading the audio-graph-card binding document I still don't see
> > > > > how the network (OMAP.McBSP3, CPCAP.Voice, MDM6600, WL1285) is
> > > > > supposed to look like. It seems to expect point-to-point DAI
> > > > > connections.
> > > > 
> > > > Ugh, a TDM mux?
> > > 
> > > Yes, at least that's how I understood Motorola's code.
> > 
> > Hmm is there some active component doing the muxing then?
> > Maybe the "AT+CMUT=0" part below?
> 
> I don't think, that there is a special hardware mux. I think each
> device is configured to use a proper timeslot and/or is being used
> exclusively.

OK. I wonder what "AT+CMUT=0" on mdm6600 then does? If a voice
call is requested and mdm6600 only has one i2s output it seems
kind of unnecesary :)

> > > > That's really unusual and not particularly supported yet, you'd
> > > > need to extend the graph card to do it.  It's where things should
> > > > end up for a generic card though.
> > > 
> > > Motorola's driver provided the following modes:
> > > 
> > > OMAP4 <-> CPCAP      (voice recording)
> > > MDM6600 <-> CPCAP    (voice call, CPU not involved)
> > > OMAP4 <-> WL1285     (bluetooth HFP/HSP)
> > > MDM6600 <-> WL1285   (bluetooth voice call)
> > > 
> > > In case of the last two variants, the bus clock is provided by
> > > CPCAP, so it needs to be enabled for any audio stream. I suppose
> > > the codec <-> codec as part of TDM is out of scope for the graph
> > > card and we need a Droid 4 specific card driver?
> > 
> > Hmm well I got audio call hacked to work as a proof of concept hack,
> > see below. Maybe it can be used to verify some of the assumptions
> > above.
> 
> Your proof of concept verifies the assumption, that the modem is
> connected to the CPCAP voice DAI. This patchset is a proof, that the
> voice DAI is connected to OMAP. So we can tell for sure, that this
> is not a common direct DAI-to-DAI connection.

OK

> > @@ -510,17 +510,17 @@
> >  07f4: 0000
> >  07f8: 0000
> >  07fc: 0000
> > -0800: 0065
> > -0804: 0000
> > -0808: 0040
> > +0800: 0025     # CPCAP_REG_VAUDIOC     VAUDIO Control
> 
> enable vaudio (obviously required :))
> 
> > +0804: 60cf     # CPCAP_REG_CC          Codec Control, moto cpcap.c:1337 sets 0x0093?
> 
> 0x6000 => clkfreq=19200000
> 
> The following bits are automatically set via DAPM by cpcap codec,
> once it is used:
> 
> 0x00c0 => "ADC Left" + "DAC Voice"
> 0x000f => "Highpass Filter TX" + "Highpass Filter RX"
> 
> > +0808: ae0a     # CPCAP_REG_CDI         Codec Digital Interface
> 
> 0xa000 => enable PLL & use clock 1
> 
> This should be used by default for VOICE DAI.
> 
> 0x0e00 => "Voice DAI Clock"=1 (handled by DAPM) , mode=I2S
> 0x000a => CPCAP_BIT_CLK_INV | CPCAP_BIT_MIC1_RX_TIMESLOT0
> 
> >  080c: 0000
> >  0810: 0004
> > -0814: 0804
> > -0818: 079c
> > -081c: 0000
> > -0820: 0924
> > -0824: 0000
> > -0828: 0000
> > +0814: 0cc0     # CPCAP_REG_TXI         TX Inputs, moto cpcap.c:1340 sets 0x0CC6?
> > +0818: 0610     # CPCAP_REG_TXMP        TX MIC PGA's, moto cpcap.c:1343 sets 0x0273?
> > +081c: 0006     # CPCAP_REG_RXOA        RX Output Amplifiers
> > +0820: 0b2c     # CPCAP_REG_RXVC        RX Volume Control
> > +0824: 0606     # CPCAP_REG_RXCOA       RX Codec to Output Amps
> > +0828: 0600     # CPCAP_REG_RXSDOA      RX Stereo DAC to Output Amps
> 
> This configures the loudspeaker, mics and volume and enables the
> required clocks/DACs/... This is already covered by the cpcap codec
> driver. You just need to configure everything correctly in
> alsamixer.
> 
> >  082c: 0400
> >  0830: 0000
> >  0834: 0030
> > 
> > I wonder if mdm6600 is the i2s master during the voice call?
> 
> I think cpcap is always the clock and frame master, but I think
> mdm6600 is the remote side and OMAP is not involved at all.

OK. So could it be just an alsamixer on/off toggle then for
"Modem" or something similar?

> > Then using the n_gsm ts 27.010 uart mux, I dial:
> > 
> > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > U0001+CFUN:OK
> > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > U0001+CMUT:OK
> > ./ngsm-rw 1 "ATD#123"		# dial number
> > U0001D:OK

There's a typo above, it should be just ATD123 where 123 is the
number.

I was just doing few test calls to robots. Payback time for all
the robocalls, you know! :)

> > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > mic yet..

And calling a person I can hear the other end but the mic is
not working. So maybe I need to tweak the alsamixer settings
too for mic?

Regards,

Tony
Pavel Machek March 29, 2018, 2:09 p.m. UTC | #3
Hi!

> Meanwhile, I can try to make voice calls more reproducable with
> qmi or MM for example instead of just n_gsm.. And then I'll try
> to fix my n_gsm pile of hacks for posting..

If you get something to work, that will be great.

If you get ofonod to work, that would be even better :-). [That's what
Jolla uses, and that's what I have graphical clients for].

Oh and.. if you have reasonable windowing system, let me know.

Best regards,
								Pavel
Tony Lindgren March 29, 2018, 2:21 p.m. UTC | #4
* Pavel Machek <pavel@ucw.cz> [180329 14:11]:
> Hi!
> 
> > Meanwhile, I can try to make voice calls more reproducable with
> > qmi or MM for example instead of just n_gsm.. And then I'll try
> > to fix my n_gsm pile of hacks for posting..
> 
> If you get something to work, that will be great.

Yeah I need to at least fix a n_gsm message handling issue that
currently causes retries and the retries have to be set artificially
high right now to avoid timeouts.. Right now each at command takes
about 30 seconds.. So I can't do any short calls :)

> If you get ofonod to work, that would be even better :-). [That's what
> Jolla uses, and that's what I have graphical clients for].

OK, I'll stick to picocom, qmicli and mmcli for now :)

> Oh and.. if you have reasonable windowing system, let me know.

I've been just using xorg and i3.

Regards,

Tony
Sebastian Reichel March 29, 2018, 3:46 p.m. UTC | #5
Hi,

On Thu, Mar 29, 2018 at 06:59:04AM -0700, Tony Lindgren wrote:
> > I think cpcap is always the clock and frame master, but I think
> > mdm6600 is the remote side and OMAP is not involved at all.
> 
> OK. So could it be just an alsamixer on/off toggle then for
> "Modem" or something similar?

I think so. We might want to have an "Mode" enum instead, though.
That can be extended, once we unlock the other modes (bluetooth,
bluetooth call).

> > > Then using the n_gsm ts 27.010 uart mux, I dial:
> > > 
> > > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > > U0001+CFUN:OK
> > > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > > U0001+CMUT:OK
> > > ./ngsm-rw 1 "ATD#123"		# dial number
> > > U0001D:OK
> 
> There's a typo above, it should be just ATD123 where 123 is the
> number.
> 
> I was just doing few test calls to robots. Payback time for all
> the robocalls, you know! :)
>
> > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > mic yet..
> 
> And calling a person I can hear the other end but the mic is
> not working. So maybe I need to tweak the alsamixer settings
> too for mic?

Your override kills most settings from alsamixer. You can try to
just override CPCAP_REG_VAUDIOC, CPCAP_REG_CC and CPCAP_REG_CDI
and setup everything else with alsamixer.

-- Sebastian
Tony Lindgren March 29, 2018, 4:06 p.m. UTC | #6
* Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180329 15:47]:
> Hi,
> 
> On Thu, Mar 29, 2018 at 06:59:04AM -0700, Tony Lindgren wrote:
> > > I think cpcap is always the clock and frame master, but I think
> > > mdm6600 is the remote side and OMAP is not involved at all.
> > 
> > OK. So could it be just an alsamixer on/off toggle then for
> > "Modem" or something similar?
> 
> I think so. We might want to have an "Mode" enum instead, though.
> That can be extended, once we unlock the other modes (bluetooth,
> bluetooth call).

OK. Seems in addition to the "Mode" enum, we also need
some other switch for modem on and off toggle?

I guess most people want to save the preferred "Mode" enum,
then for the duration of the call enable the selected mode.

And I guess the mute is already there for the mic with 'm'
in alsamixer for conf calls :)

> > > > Then using the n_gsm ts 27.010 uart mux, I dial:
> > > > 
> > > > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > > > U0001+CFUN:OK
> > > > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > > > U0001+CMUT:OK
> > > > ./ngsm-rw 1 "ATD#123"		# dial number
> > > > U0001D:OK
> > 
> > There's a typo above, it should be just ATD123 where 123 is the
> > number.
> > 
> > I was just doing few test calls to robots. Payback time for all
> > the robocalls, you know! :)
> >
> > > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > > mic yet..
> > 
> > And calling a person I can hear the other end but the mic is
> > not working. So maybe I need to tweak the alsamixer settings
> > too for mic?
> 
> Your override kills most settings from alsamixer. You can try to
> just override CPCAP_REG_VAUDIOC, CPCAP_REG_CC and CPCAP_REG_CDI
> and setup everything else with alsamixer.

OK I'll try to narrow it down and play with the mic settings
tonight or over the weekend.

Regards,

Tony
Pavel Machek March 29, 2018, 4:08 p.m. UTC | #7
Hi!

> @@ -510,17 +510,17 @@
>  07f4: 0000
>  07f8: 0000
>  07fc: 0000
> -0800: 0065
> -0804: 0000
> -0808: 0040
> +0800: 0025     # CPCAP_REG_VAUDIOC     VAUDIO Control
> +0804: 60cf     # CPCAP_REG_CC          Codec Control, moto cpcap.c:1337 sets 0x0093?
> +0808: ae0a     # CPCAP_REG_CDI         Codec Digital Interface
>  080c: 0000
>  0810: 0004
> -0814: 0804
> -0818: 079c
> -081c: 0000
> -0820: 0924
> -0824: 0000
> -0828: 0000
> +0814: 0cc0     # CPCAP_REG_TXI         TX Inputs, moto cpcap.c:1340 sets 0x0CC6?
> +0818: 0610     # CPCAP_REG_TXMP        TX MIC PGA's, moto cpcap.c:1343 sets 0x0273?
> +081c: 0006     # CPCAP_REG_RXOA        RX Output Amplifiers
> +0820: 0b2c     # CPCAP_REG_RXVC        RX Volume Control
> +0824: 0606     # CPCAP_REG_RXCOA       RX Codec to Output Amps
> +0828: 0600     # CPCAP_REG_RXSDOA      RX Stereo DAC to Output Amps
>  082c: 0400
>  0830: 0000
>  0834: 0030
> 
> I wonder if mdm6600 is the i2s master during the voice call?
> 
> Then using the n_gsm ts 27.010 uart mux, I dial:
> 
> ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> U0001+CFUN:OK
> ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> U0001+CMUT:OK
> ./ngsm-rw 1 "ATD#123"		# dial number
> U0001D:OK
> 
> And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> mic yet..

Hehe, ok, that's fun! I don't need +CMUT=0. It gave me error but then
the call worked, anyway... (I'm working with ttyUSB4).

I don't know how to hang the call up. ATH did not work for me.

And no, microphone does not work.

Thanks!
									Pavel
Tony Lindgren March 29, 2018, 4:34 p.m. UTC | #8
* Pavel Machek <pavel@ucw.cz> [180329 16:09]:
> > Then using the n_gsm ts 27.010 uart mux, I dial:
> > 
> > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > U0001+CFUN:OK
> > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > U0001+CMUT:OK
> > ./ngsm-rw 1 "ATD#123"		# dial number
> > U0001D:OK
> > 
> > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > mic yet..
> 
> Hehe, ok, that's fun! I don't need +CMUT=0. It gave me error but then
> the call worked, anyway... (I'm working with ttyUSB4).

Oh interesting. So maybe Android is doing AT+CMUT=0 for some other
modems and it's not really needed? Or you have settings preserved
from warm boot from Android?

I did not have any luck with ttyUSB4 last night. Did you dial with
ATD123; or ATD123? So is the semicolon really needed?

> I don't know how to hang the call up. ATH did not work for me.

OK ATH works for me on n_gsm channel 1.

> And no, microphone does not work.

Yeah so conf calls only for now.

Tony
Pavel Machek March 29, 2018, 4:37 p.m. UTC | #9
Hi!

> > > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > > mic yet..
> > 
> > And calling a person I can hear the other end but the mic is
> > not working. So maybe I need to tweak the alsamixer settings
> > too for mic?
> 
> Your override kills most settings from alsamixer. You can try to
> just override CPCAP_REG_VAUDIOC, CPCAP_REG_CC and CPCAP_REG_CDI
> and setup everything else with alsamixer.

I tried that, and could not get it to work; will try some more.

Is there easy way to get the register dump?

Thanks,
									Pavel
Tony Lindgren March 29, 2018, 4:41 p.m. UTC | #10
* Pavel Machek <pavel@ucw.cz> [180329 16:38]:
> Hi!
> 
> > > > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > > > mic yet..
> > > 
> > > And calling a person I can hear the other end but the mic is
> > > not working. So maybe I need to tweak the alsamixer settings
> > > too for mic?
> > 
> > Your override kills most settings from alsamixer. You can try to
> > just override CPCAP_REG_VAUDIOC, CPCAP_REG_CC and CPCAP_REG_CDI
> > and setup everything else with alsamixer.
> 
> I tried that, and could not get it to work; will try some more.
> 
> Is there easy way to get the register dump?

For mainline kernel:

# cat /sys/kernel/debug/regmap/spi0.0/registers

For Android v3.0.8 kernel, see cpcaprw on github.

Regards,

Tony
Pavel Machek March 29, 2018, 6:05 p.m. UTC | #11
On Thu 2018-03-29 09:34:50, Tony Lindgren wrote:
> * Pavel Machek <pavel@ucw.cz> [180329 16:09]:
> > > Then using the n_gsm ts 27.010 uart mux, I dial:
> > > 
> > > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > > U0001+CFUN:OK
> > > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > > U0001+CMUT:OK
> > > ./ngsm-rw 1 "ATD#123"		# dial number
> > > U0001D:OK
> > > 
> > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > mic yet..
> > 
> > Hehe, ok, that's fun! I don't need +CMUT=0. It gave me error but then
> > the call worked, anyway... (I'm working with ttyUSB4).
> 
> Oh interesting. So maybe Android is doing AT+CMUT=0 for some other
> modems and it's not really needed? Or you have settings preserved
> from warm boot from Android?

No idea. But I booted from recovery, and I had to power up modem using
+CFUN...

> I did not have any luck with ttyUSB4 last night. Did you dial with
> ATD123; or ATD123? So is the semicolon really needed?
>

AT+CFUN=1
OK
ATD800123456
NO CARRIER
ATD800123456;
OK

I seem to need semicolon. And yes, I tried again after the call. Still
says no carrier.

Hmm. And when calling test number, the modem failed:
>
[  438.236755] Somebody do a proper driver please cpcap_soc_work
[  495.496032] phy-mapphone-mdm6600 usb-phy@1: modem status: 0 off
[  499.406005] phy-mapphone-mdm6600 usb-phy@1: modem status: 0 off
[  499.407318] usb 2-1: USB disconnect, device number 2
[  499.424926] qcserial ttyUSB0: Qualcomm USB modem converter now
disconnected from ttyUSB0
[  499.434112] qcserial 2-1:1.0: device disconnected
[  499.443389] qcserial ttyUSB1: Qualcomm USB modem converter now
disconnected from ttyUSB1
[  499.451904] qcserial 2-1:1.1: device disconnected
[  499.460968] qcserial ttyUSB2: Qualcomm USB modem converter now
disconnected from ttyUSB2
[  499.469512] qcserial 2-1:1.2: device disconnected
[  499.478057] qcserial ttyUSB3: Qualcomm USB modem converter now
disconnected from ttyUSB3
[  499.486572] qcserial 2-1:1.3: device disconnected
[  499.504760] qcserial ttyUSB4: Qualcomm USB modem converter now
disconnected from ttyUSB4
[  499.513244] qcserial 2-1:1.4: device disconnected
[  499.519104] qmi_wwan 2-1:1.5 wwan0: unregister 'qmi_wwan'
usb-4a064800.ohci-1, WWAN/QMI device
[  499.611511] qmi_wwan 2-1:1.6 wwan1: unregister 'qmi_wwan'
usb-4a064800.ohci-1, WWAN/QMI device
[  499.676086] Somebody do a proper driver please cpcap_soc_work
[  499.688323] qmi_wwan 2-1:1.7 wwan2: unregister 'qmi_wwan'
usb-4a064800.ohci-1, WWAN/QMI device
[  499.768859] qmi_wwan 2-1:1.8 wwan3: unregister 'qmi_wwan'
usb-4a064800.ohci-1, WWAN/QMI device

That one will be fun to debug, I'm afraid. (Or does the message at
495.496032 mean that we turned it off?)

Best regards,
									Pavel
Tony Lindgren March 29, 2018, 9:58 p.m. UTC | #12
* Pavel Machek <pavel@ucw.cz> [180329 18:07]:
> On Thu 2018-03-29 09:34:50, Tony Lindgren wrote:
> > * Pavel Machek <pavel@ucw.cz> [180329 16:09]:
> > > > Then using the n_gsm ts 27.010 uart mux, I dial:
> > > > 
> > > > ./ngsm-rw 1 "AT+CFUN=1"		# connect to network
> > > > U0001+CFUN:OK
> > > > ./ngsm-rw 2 "AT+CMUT=0"		# unmute speaker over ch2, do this over qmi?
> > > > U0001+CMUT:OK
> > > > ./ngsm-rw 1 "ATD#123"		# dial number
> > > > U0001D:OK
> > > > 
> > > > And I do hear a voice talking over the speakerphone :) Sorry have not tested the
> > > > mic yet..
> > > 
> > > Hehe, ok, that's fun! I don't need +CMUT=0. It gave me error but then
> > > the call worked, anyway... (I'm working with ttyUSB4).
> > 
> > Oh interesting. So maybe Android is doing AT+CMUT=0 for some other
> > modems and it's not really needed? Or you have settings preserved
> > from warm boot from Android?
> 
> No idea. But I booted from recovery, and I had to power up modem using
> +CFUN...
> 
> > I did not have any luck with ttyUSB4 last night. Did you dial with
> > ATD123; or ATD123? So is the semicolon really needed?
> >
> 
> AT+CFUN=1
> OK
> ATD800123456
> NO CARRIER
> ATD800123456;
> OK
> 
> I seem to need semicolon. And yes, I tried again after the call. Still
> says no carrier.

OK thanks for confirming that.

> Hmm. And when calling test number, the modem failed:
> >
> [  438.236755] Somebody do a proper driver please cpcap_soc_work
> [  495.496032] phy-mapphone-mdm6600 usb-phy@1: modem status: 0 off
> [  499.406005] phy-mapphone-mdm6600 usb-phy@1: modem status: 0 off
> [  499.407318] usb 2-1: USB disconnect, device number 2
> [  499.424926] qcserial ttyUSB0: Qualcomm USB modem converter now
> disconnected from ttyUSB0
> [  499.434112] qcserial 2-1:1.0: device disconnected
> [  499.443389] qcserial ttyUSB1: Qualcomm USB modem converter now
> disconnected from ttyUSB1
> [  499.451904] qcserial 2-1:1.1: device disconnected
> [  499.460968] qcserial ttyUSB2: Qualcomm USB modem converter now
> disconnected from ttyUSB2
> [  499.469512] qcserial 2-1:1.2: device disconnected
> [  499.478057] qcserial ttyUSB3: Qualcomm USB modem converter now
> disconnected from ttyUSB3
> [  499.486572] qcserial 2-1:1.3: device disconnected
> [  499.504760] qcserial ttyUSB4: Qualcomm USB modem converter now
> disconnected from ttyUSB4
> [  499.513244] qcserial 2-1:1.4: device disconnected
> [  499.519104] qmi_wwan 2-1:1.5 wwan0: unregister 'qmi_wwan'
> usb-4a064800.ohci-1, WWAN/QMI device
> [  499.611511] qmi_wwan 2-1:1.6 wwan1: unregister 'qmi_wwan'
> usb-4a064800.ohci-1, WWAN/QMI device
> [  499.676086] Somebody do a proper driver please cpcap_soc_work
> [  499.688323] qmi_wwan 2-1:1.7 wwan2: unregister 'qmi_wwan'
> usb-4a064800.ohci-1, WWAN/QMI device
> [  499.768859] qmi_wwan 2-1:1.8 wwan3: unregister 'qmi_wwan'
> usb-4a064800.ohci-1, WWAN/QMI device
> 
> That one will be fun to debug, I'm afraid. (Or does the message at
> 495.496032 mean that we turned it off?)

Looks like mdm6600 either entered low-power mode, or hung?
If it hung, it's internal watchdog might bring it back after
a while.

If it entered low-power mode, in theory we should see the state
change interrupt that's handled by phy-mapphone-mdm6600.c.
I never managed to do that so far so maybe you figured it out
with some command.

Regards,

Tony
Sebastian Reichel March 30, 2018, 10:57 a.m. UTC | #13
Hi,

On Thu, Mar 29, 2018 at 09:06:11AM -0700, Tony Lindgren wrote:
> * Sebastian Reichel <sebastian.reichel@collabora.co.uk> [180329 15:47]:
> > Hi,
> > 
> > On Thu, Mar 29, 2018 at 06:59:04AM -0700, Tony Lindgren wrote:
> > > > I think cpcap is always the clock and frame master, but I think
> > > > mdm6600 is the remote side and OMAP is not involved at all.
> > > 
> > > OK. So could it be just an alsamixer on/off toggle then for
> > > "Modem" or something similar?
> > 
> > I think so. We might want to have an "Mode" enum instead, though.
> > That can be extended, once we unlock the other modes (bluetooth,
> > bluetooth call).
> 
> OK. Seems in addition to the "Mode" enum, we also need
> some other switch for modem on and off toggle?

I don't think so. DAPM should automatically power on/off the
modem if there is a valid path from some CPCAP output/input.
Since the mode enum will "disconnect" the modem in the DAPM
graph, it should be enabled/disabled automatically.

> I guess most people want to save the preferred "Mode" enum,
> then for the duration of the call enable the selected mode.
> 
> And I guess the mute is already there for the mic with 'm'
> in alsamixer for conf calls :)

Yes.

-- Sebastian
Pavel Machek March 30, 2018, 10:31 p.m. UTC | #14
Hi!

> > Your override kills most settings from alsamixer. You can try to
> > just override CPCAP_REG_VAUDIOC, CPCAP_REG_CC and CPCAP_REG_CDI
> > and setup everything else with alsamixer.
> 
> OK I'll try to narrow it down and play with the mic settings
> tonight or over the weekend.

No, just the three+alsamixer will not work. You also need to

814: |= 400

824: |= 400 CPCAP_REG_RXCOA : CPCAP_BIT_PGA_CDC_EN
81c: |= 006 CPCAP_REG_RXOA : CPCAP_BIT_A2_LDSP_L_EN / CPCAP_BIT_A2_LDSP_R_EN

You can set those using sudo aplay -D plughw:CARD=Audio,DEV=1
/usr/share/sounds/alsa/Front_Left.wav ... but that will do bad stuff
to the rest of the bits.

You might find this useful:

 watch 'cat /sys/kernel/debug/regmap/spi0.0/registers | grep "0800\|0804\|0808\|0814\|0818\|081c\|0820\|0824\|0828"'

Good luck, I need some sleep,

									Pavel
Tony Lindgren April 1, 2018, 11:17 p.m. UTC | #15
* Tony Lindgren <tony@atomide.com> [180329 22:00]:
> If it entered low-power mode, in theory we should see the state
> change interrupt that's handled by phy-mapphone-mdm6600.c.
> I never managed to do that so far so maybe you figured it out
> with some command.

And looks like the trigger to mdm6600 to enter low power states
is done via USB:

# echo auto > /sys/devices/platform/44000000.ocp/4a064000.usbhshost/4a064800.ohci/usb1/1-1/power/level

Looks like with that and modem enabled I'm seeing 207mW power
consumption on a and idle system with screen off on my power supply.
Opening /dev/ttyUSB4 makes the power consumption go up to 502mW..
So now we need the wakeirqs and PM runtime to work for ohci and
then the device can be used for few hours on batteries.

Regards,

Tony
diff mbox

Patch

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -251,6 +251,8 @@  struct cpcap_audio {
 	int codec_clk_id;
 	int codec_freq;
 	int codec_format;
+
+	struct delayed_work work;
 };
 
 static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
@@ -1500,6 +1502,57 @@  static int cpcap_audio_reset(struct snd_soc_component *component,
 	return 0;
 }
 
+static void cpcap_soc_work(struct work_struct *work)
+{
+	struct cpcap_audio *cpcap = container_of(work,
+						 struct cpcap_audio,
+						 work.work);
+	struct device *dev = cpcap->component->dev;
+	int error;
+
+	dev_info(dev, "Somebody do a proper driver please %s\n", __func__);
+
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
+				   0xffff, 0x0025);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
+				   0xffff, 0x60cf);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+				   0xffff, 0xae0a);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+				   0xffff, 0x0cc0);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXMP,
+				   0xffff, 0x0610);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
+				   0xffff, 0x0006);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXVC,
+				   0xffff, 0x0b2c);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+				   0xffff, 0x0606);
+	if (error)
+		goto out;
+	error = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
+				   0xffff, 0x0600);
+	if (error)
+		goto out;
+
+out:
+	schedule_delayed_work(&cpcap->work, msecs_to_jiffies(1000));
+}
+
 static int cpcap_soc_probe(struct snd_soc_component *component)
 {
 	struct cpcap_audio *cpcap;
@@ -1520,11 +1573,26 @@  static int cpcap_soc_probe(struct snd_soc_component *component)
 	if (err)
 		return err;
 
-	return cpcap_audio_reset(component, false);
+	err = cpcap_audio_reset(component, false);
+	if (err)
+		return err;
+
+	INIT_DELAYED_WORK(&cpcap->work, cpcap_soc_work);
+	schedule_delayed_work(&cpcap->work, msecs_to_jiffies(1000));
+
+	return 0;
+}
+
+static void cpcap_soc_remove(struct snd_soc_component *component)
+{
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+	cancel_delayed_work_sync(&cpcap->work);
 }
 
 static struct snd_soc_component_driver soc_codec_dev_cpcap = {
 	.probe			= cpcap_soc_probe,
+	.remove			= cpcap_soc_remove,
 	.controls		= cpcap_snd_controls,
 	.num_controls		= ARRAY_SIZE(cpcap_snd_controls),
 	.dapm_widgets		= cpcap_dapm_widgets,