2018-02-23 20:08:20

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 0/5] Motorola Droid 4 Audio Support

Hi,

This adds audio support to Motorola Droid 4. I dropped the
regulator from the DT binding as requested by Mark.

Tested:
- Playing via both DACs using Speaker, Earpiece, Headphone
- Recording using internal Mic
- Volume Controls

Known not to work:
- 3.5mm detection support (requires closed source firmware,
needs further investigation)
- Modem / Bluetooth Audio (this needs something more sophisticated
than the audio-graph-card driver. I will have a look once
the basic support has been merged)

Changes since PATCHv4:
* Replace verbose GPL text with SPDX header
* Use "GPL v2" as MODULE_LICENSE
* Drop "default MFD_CPCAP" for the codec driver
* Use SOC_SINGLE instead of SOC_ENUM for Phase invert switches
* Find DT node by node name instead of by compatible property
- Drop Acked-by from Rob Herring
* Add new patch for MFD driver to implement the mentioned
DT change

Changes since PATCHv3:
* Drop regulator from DT binding, request VAUDIO from
global regulator namespace instead

Changes since PATCHv2:
* Fix a whitespace issue
* Fix const notes Takashi provided
* Fix a DAPM route issue I accidently introduced in v2

Changes since PATCHv1:
* Add patch from Tony exporting soc_dpcm_runtime_update
* Integrate DT patch for vaudio initial mode
* Split dt-binding from codec patch and add Ack from Rob
* Fix CPCAP position in Kconfig/Makefile
* Avoid "err +=" constructs
* Simplify reset function
* Drop cpcap_audio_read/write helpers
* Do not use tertiary operator for mute register value
* Update Input Mux logic
* Switch from simple-audio-card to audio-graph-card

-- Sebastian

Sebastian Reichel (5):
dt-bindings: mfd: motorola-cpcap: document audio-codec
ASoC: codec: cpcap: new codec
mfd: motorola-cpcap: Add audio-codec support
ARM: dts: motorola-cpcap-mapphone: add audio-codec
ARM: dts: omap4-droid4: add soundcard

.../devicetree/bindings/mfd/motorola-cpcap.txt | 42 +
arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 13 +
arch/arm/boot/dts/omap4-droid4-xt894.dts | 78 +
drivers/mfd/motorola-cpcap.c | 51 +-
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cpcap.c | 1568 ++++++++++++++++++++
7 files changed, 1757 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/codecs/cpcap.c

--
2.16.1



2018-02-23 20:05:20

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

From: Sebastian Reichel <[email protected]>

Add support for the audio-codec node by converting from
devm_of_platform_populate() to devm_mfd_add_devices().

Signed-off-by: Sebastian Reichel <[email protected]>
---
drivers/mfd/motorola-cpcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index d2cc1eabac05..f6c79a4ccb55 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -18,6 +18,7 @@
#include <linux/regmap.h>
#include <linux/sysfs.h>

+#include <linux/mfd/core.h>
#include <linux/mfd/motorola-cpcap.h>
#include <linux/spi/spi.h>

@@ -216,6 +217,53 @@ static const struct regmap_config cpcap_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};

+static const struct mfd_cell cpcap_mfd_devices[] = {
+ {
+ .name = "cpcap_adc",
+ .of_compatible = "motorola,mapphone-cpcap-adc",
+ }, {
+ .name = "cpcap_battery",
+ .of_compatible = "motorola,cpcap-battery",
+ }, {
+ .name = "cpcap-charger",
+ .of_compatible = "motorola,mapphone-cpcap-charger",
+ }, {
+ .name = "cpcap-regulator",
+ .of_compatible = "motorola,mapphone-cpcap-regulator",
+ }, {
+ .name = "cpcap-rtc",
+ .of_compatible = "motorola,cpcap-rtc",
+ }, {
+ .name = "cpcap-pwrbutton",
+ .of_compatible = "motorola,cpcap-pwrbutton",
+ }, {
+ .name = "cpcap-usb-phy",
+ .of_compatible = "motorola,mapphone-cpcap-usb-phy",
+ }, {
+ .name = "cpcap-led",
+ .id = 0,
+ .of_compatible = "motorola,cpcap-led-red",
+ }, {
+ .name = "cpcap-led",
+ .id = 1,
+ .of_compatible = "motorola,cpcap-led-green",
+ }, {
+ .name = "cpcap-led",
+ .id = 2,
+ .of_compatible = "motorola,cpcap-led-blue",
+ }, {
+ .name = "cpcap-led",
+ .id = 3,
+ .of_compatible = "motorola,cpcap-led-adl",
+ }, {
+ .name = "cpcap-led",
+ .id = 4,
+ .of_compatible = "motorola,cpcap-led-cp",
+ }, {
+ .name = "cpcap-codec",
+ }
+};
+
static int cpcap_probe(struct spi_device *spi)
{
const struct of_device_id *match;
@@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
if (ret)
return ret;

- return devm_of_platform_populate(&cpcap->spi->dev);
+ return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
+ ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
}

static struct spi_driver cpcap_driver = {
--
2.16.1


2018-02-23 20:05:28

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 5/5] ARM: dts: omap4-droid4: add soundcard

Add sound support to Motorola Droid 4 using simple-soundcard
and CPCAP's audio codec. This does not yet correctly represent
the whole audio routing, since McBSP3 is also connected to
Bluetooth and MDM6600 modem (and probably also 4G modem).
These extra DAI links are not yet supported and have not been
tested.

Signed-off-by: Sebastian Reichel <[email protected]>
---
arch/arm/boot/dts/omap4-droid4-xt894.dts | 78 ++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)

diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts
index e11a24397163..fc30d375883a 100644
--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts
+++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts
@@ -118,6 +118,26 @@

};
};
+
+ soundcard {
+ compatible = "audio-graph-card";
+ label = "Droid 4 Audio";
+
+ simple-graph-card,widgets =
+ "Speaker", "Earpiece",
+ "Speaker", "Loudspeaker",
+ "Headphone", "Headphone Jack",
+ "Microphone", "Internal Mic";
+
+ simple-graph-card,routing =
+ "Earpiece", "EP",
+ "Loudspeaker", "SPKR",
+ "Headphone Jack", "HSL",
+ "Headphone Jack", "HSR",
+ "MICR", "Internal Mic";
+
+ dais = <&mcbsp2_port>, <&mcbsp3_port>;
+ };
};

&dss {
@@ -515,6 +535,24 @@
OMAP4_IOPAD(0x112, PIN_OUTPUT_PULLUP | MUX_MODE5) /* uart4_rts */
>;
};
+
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_clkx */
+ OMAP4_IOPAD(0x0f8, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_dr */
+ OMAP4_IOPAD(0x0fa, PIN_OUTPUT | MUX_MODE0) /* abe_mcbsp2_dx */
+ OMAP4_IOPAD(0x0fc, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_fsx */
+ >;
+ };
+
+ mcbsp3_pins: pinmux_mcbsp3_pins {
+ pinctrl-single,pins = <
+ OMAP4_IOPAD(0x106, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_dr */
+ OMAP4_IOPAD(0x108, PIN_OUTPUT | MUX_MODE1) /* abe_mcbsp3_dx */
+ OMAP4_IOPAD(0x10a, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_clkx */
+ OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_fsx */
+ >;
+ };
};

&omap4_pmx_wkup {
@@ -600,3 +638,43 @@
"0", "0", "1";
};
};
+
+&mcbsp2 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp2_pins>;
+ status = "okay";
+
+ mcbsp2_port: port {
+ cpu_dai2: endpoint {
+ dai-format = "i2s";
+ remote-endpoint = <&cpcap_audio_codec0>;
+ frame-master = <&cpcap_audio_codec0>;
+ bitclock-master = <&cpcap_audio_codec0>;
+ };
+ };
+};
+
+&mcbsp3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp3_pins>;
+ status = "okay";
+
+ mcbsp3_port: port {
+ cpu_dai3: endpoint {
+ dai-format = "dsp_a";
+ frame-master = <&cpcap_audio_codec1>;
+ bitclock-master = <&cpcap_audio_codec1>;
+ remote-endpoint = <&cpcap_audio_codec1>;
+ };
+ };
+};
+
+&cpcap_audio_codec0 {
+ remote-endpoint = <&cpu_dai2>;
+};
+
+&cpcap_audio_codec1 {
+ remote-endpoint = <&cpu_dai3>;
+};
--
2.16.1


2018-02-23 20:07:05

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 4/5] ARM: dts: motorola-cpcap-mapphone: add audio-codec

Add node for audio-codec to its DT file.

Signed-off-by: Sebastian Reichel <[email protected]>
---
arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index 4d61e5b1334a..ddc7a7bb33c0 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -68,6 +68,19 @@
};
};

+ cpcap_audio: audio-codec {
+ #sound-dai-cells = <1>;
+
+ port@0 {
+ cpcap_audio_codec0: endpoint {
+ };
+ };
+ port@1 {
+ cpcap_audio_codec1: endpoint {
+ };
+ };
+ };
+
cpcap_rtc: rtc {
compatible = "motorola,cpcap-rtc";

--
2.16.1


2018-02-23 20:07:15

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 1/5] dt-bindings: mfd: motorola-cpcap: document audio-codec

This adds the DT binding for the audio-codec sub-module found
inside the Motorola CPCAP PMIC.

Signed-off-by: Sebastian Reichel <[email protected]>
---
.../devicetree/bindings/mfd/motorola-cpcap.txt | 42 ++++++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt b/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
index 15bc885f9df4..82c3a7140660 100644
--- a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
+++ b/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
@@ -12,6 +12,30 @@ Required properties:
- spi-max-frequency : Typically set to 3000000
- spi-cs-high : SPI chip select direction

+Optional subnodes:
+
+The sub-functions of CPCAP get their own node with their own compatible values,
+which are described in the following files:
+
+- Documentation/devicetree/bindings/power/supply/cpcap-battery.txt
+- Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
+- Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
+- Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt
+- Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
+- Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
+- Documentation/devicetree/bindings/leds/leds-cpcap.txt
+- Documentation/devicetree/bindings/iio/adc/cpcap-adc.txt
+
+The only exception is the audio codec. Instead of a compatible value its
+node must be named "audio-codec".
+
+Required properties for the audio-codec subnode:
+
+- #sound-dai-cells = <1>;
+
+The audio-codec provides two DAIs. The first one is connected to the
+Stereo HiFi DAC and the second one is connected to the Voice DAC.
+
Example:

&mcspi1 {
@@ -26,6 +50,24 @@ Example:
#size-cells = <0>;
spi-max-frequency = <3000000>;
spi-cs-high;
+
+ audio-codec {
+ #sound-dai-cells = <1>;
+
+ /* HiFi */
+ port@0 {
+ endpoint {
+ remote-endpoint = <&cpu_dai1>;
+ };
+ };
+
+ /* Voice */
+ port@1 {
+ endpoint {
+ remote-endpoint = <&cpu_dai2>;
+ };
+ };
+ };
};
};

--
2.16.1


2018-02-23 20:08:32

by Sebastian Reichel

[permalink] [raw]
Subject: [PATCHv5 2/5] ASoC: codec: cpcap: new codec

Motorola CPCAP is a PMIC with audio functionality, that can be
found on Motorola Droid 4 and probably a few other phones from
Motorola's Droid series.

The driver has been written from scratch using Motorola's Android
driver, register dumps from running Android and datasheet for NXP
MC13783UG (which is similar to Motorola CPCAP, but not the same).

The chip provides two audio interfaces, that can be muxed to two
different audio codecs. One provides support for stereo output
(named StDAC or HiFi), while the other only provides mono output
(named Voice). Only the Voice codec provides a Capture interface.

Signed-off-by: Sebastian Reichel <[email protected]>
---
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cpcap.c | 1568 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1574 insertions(+)
create mode 100644 sound/soc/codecs/cpcap.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 2b331f7266ab..5bd94841feb6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -408,6 +408,10 @@ config SND_SOC_ALC5632
config SND_SOC_BT_SCO
tristate "Dummy BT SCO codec driver"

+config SND_SOC_CPCAP
+ tristate "Motorola CPCAP codec"
+ depends on MFD_CPCAP
+
config SND_SOC_CQ0093VC
tristate

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index da1571336f1e..2aeee1ba034e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -36,6 +36,7 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-bt-sco-objs := bt-sco.o
+snd-soc-cpcap-objs := cpcap.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs35l33-objs := cs35l33.o
@@ -282,6 +283,7 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
new file mode 100644
index 000000000000..aedb267d4581
--- /dev/null
+++ b/sound/soc/codecs/cpcap.c
@@ -0,0 +1,1568 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC CPCAP codec driver
+ *
+ * Copyright (C) 2017 - 2018 Sebastian Reichel <[email protected]>
+ *
+ * Very loosely based on original driver from Motorola:
+ * Copyright (C) 2007 - 2009 Motorola, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+/* Register 513 CPCAP_REG_CC --- CODEC */
+#define CPCAP_BIT_CDC_CLK2 15
+#define CPCAP_BIT_CDC_CLK1 14
+#define CPCAP_BIT_CDC_CLK0 13
+#define CPCAP_BIT_CDC_SR3 12
+#define CPCAP_BIT_CDC_SR2 11
+#define CPCAP_BIT_CDC_SR1 10
+#define CPCAP_BIT_CDC_SR0 9
+#define CPCAP_BIT_CDC_CLOCK_TREE_RESET 8
+#define CPCAP_BIT_MIC2_CDC_EN 7
+#define CPCAP_BIT_CDC_EN_RX 6
+#define CPCAP_BIT_DF_RESET 5
+#define CPCAP_BIT_MIC1_CDC_EN 4
+#define CPCAP_BIT_AUDOHPF_1 3
+#define CPCAP_BIT_AUDOHPF_0 2
+#define CPCAP_BIT_AUDIHPF_1 1
+#define CPCAP_BIT_AUDIHPF_0 0
+
+/* Register 514 CPCAP_REG_CDI --- CODEC Digital Audio Interface */
+#define CPCAP_BIT_CDC_PLL_SEL 15
+#define CPCAP_BIT_CLK_IN_SEL 13
+#define CPCAP_BIT_DIG_AUD_IN 12
+#define CPCAP_BIT_CDC_CLK_EN 11
+#define CPCAP_BIT_CDC_DIG_AUD_FS1 10
+#define CPCAP_BIT_CDC_DIG_AUD_FS0 9
+#define CPCAP_BIT_MIC2_TIMESLOT2 8
+#define CPCAP_BIT_MIC2_TIMESLOT1 7
+#define CPCAP_BIT_MIC2_TIMESLOT0 6
+#define CPCAP_BIT_MIC1_RX_TIMESLOT2 5
+#define CPCAP_BIT_MIC1_RX_TIMESLOT1 4
+#define CPCAP_BIT_MIC1_RX_TIMESLOT0 3
+#define CPCAP_BIT_FS_INV 2
+#define CPCAP_BIT_CLK_INV 1
+#define CPCAP_BIT_SMB_CDC 0
+
+/* Register 515 CPCAP_REG_SDAC --- Stereo DAC */
+#define CPCAP_BIT_FSYNC_CLK_IN_COMMON 11
+#define CPCAP_BIT_SLAVE_PLL_CLK_INPUT 10
+#define CPCAP_BIT_ST_CLOCK_TREE_RESET 9
+#define CPCAP_BIT_DF_RESET_ST_DAC 8
+#define CPCAP_BIT_ST_SR3 7
+#define CPCAP_BIT_ST_SR2 6
+#define CPCAP_BIT_ST_SR1 5
+#define CPCAP_BIT_ST_SR0 4
+#define CPCAP_BIT_ST_DAC_CLK2 3
+#define CPCAP_BIT_ST_DAC_CLK1 2
+#define CPCAP_BIT_ST_DAC_CLK0 1
+#define CPCAP_BIT_ST_DAC_EN 0
+
+/* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */
+#define CPCAP_BIT_ST_L_TIMESLOT2 13
+#define CPCAP_BIT_ST_L_TIMESLOT1 12
+#define CPCAP_BIT_ST_L_TIMESLOT0 11
+#define CPCAP_BIT_ST_R_TIMESLOT2 10
+#define CPCAP_BIT_ST_R_TIMESLOT1 9
+#define CPCAP_BIT_ST_R_TIMESLOT0 8
+#define CPCAP_BIT_ST_DAC_CLK_IN_SEL 7
+#define CPCAP_BIT_ST_FS_INV 6
+#define CPCAP_BIT_ST_CLK_INV 5
+#define CPCAP_BIT_ST_DIG_AUD_FS1 4
+#define CPCAP_BIT_ST_DIG_AUD_FS0 3
+#define CPCAP_BIT_DIG_AUD_IN_ST_DAC 2
+#define CPCAP_BIT_ST_CLK_EN 1
+#define CPCAP_BIT_SMB_ST_DAC 0
+
+/* Register 517 CPCAP_REG_TXI --- TX Interface */
+#define CPCAP_BIT_PTT_TH 15
+#define CPCAP_BIT_PTT_CMP_EN 14
+#define CPCAP_BIT_HS_ID_TX 13
+#define CPCAP_BIT_MB_ON2 12
+#define CPCAP_BIT_MB_ON1L 11
+#define CPCAP_BIT_MB_ON1R 10
+#define CPCAP_BIT_RX_L_ENCODE 9
+#define CPCAP_BIT_RX_R_ENCODE 8
+#define CPCAP_BIT_MIC2_MUX 7
+#define CPCAP_BIT_MIC2_PGA_EN 6
+#define CPCAP_BIT_CDET_DIS 5
+#define CPCAP_BIT_EMU_MIC_MUX 4
+#define CPCAP_BIT_HS_MIC_MUX 3
+#define CPCAP_BIT_MIC1_MUX 2
+#define CPCAP_BIT_MIC1_PGA_EN 1
+#define CPCAP_BIT_DLM 0
+
+/* Register 518 CPCAP_REG_TXMP --- Mic Gain */
+#define CPCAP_BIT_MB_BIAS_R1 11
+#define CPCAP_BIT_MB_BIAS_R0 10
+#define CPCAP_BIT_MIC2_GAIN_4 9
+#define CPCAP_BIT_MIC2_GAIN_3 8
+#define CPCAP_BIT_MIC2_GAIN_2 7
+#define CPCAP_BIT_MIC2_GAIN_1 6
+#define CPCAP_BIT_MIC2_GAIN_0 5
+#define CPCAP_BIT_MIC1_GAIN_4 4
+#define CPCAP_BIT_MIC1_GAIN_3 3
+#define CPCAP_BIT_MIC1_GAIN_2 2
+#define CPCAP_BIT_MIC1_GAIN_1 1
+#define CPCAP_BIT_MIC1_GAIN_0 0
+
+/* Register 519 CPCAP_REG_RXOA --- RX Output Amplifier */
+#define CPCAP_BIT_UNUSED_519_15 15
+#define CPCAP_BIT_UNUSED_519_14 14
+#define CPCAP_BIT_UNUSED_519_13 13
+#define CPCAP_BIT_STDAC_LOW_PWR_DISABLE 12
+#define CPCAP_BIT_HS_LOW_PWR 11
+#define CPCAP_BIT_HS_ID_RX 10
+#define CPCAP_BIT_ST_HS_CP_EN 9
+#define CPCAP_BIT_EMU_SPKR_R_EN 8
+#define CPCAP_BIT_EMU_SPKR_L_EN 7
+#define CPCAP_BIT_HS_L_EN 6
+#define CPCAP_BIT_HS_R_EN 5
+#define CPCAP_BIT_A4_LINEOUT_L_EN 4
+#define CPCAP_BIT_A4_LINEOUT_R_EN 3
+#define CPCAP_BIT_A2_LDSP_L_EN 2
+#define CPCAP_BIT_A2_LDSP_R_EN 1
+#define CPCAP_BIT_A1_EAR_EN 0
+
+/* Register 520 CPCAP_REG_RXVC --- RX Volume Control */
+#define CPCAP_BIT_VOL_EXT3 15
+#define CPCAP_BIT_VOL_EXT2 14
+#define CPCAP_BIT_VOL_EXT1 13
+#define CPCAP_BIT_VOL_EXT0 12
+#define CPCAP_BIT_VOL_DAC3 11
+#define CPCAP_BIT_VOL_DAC2 10
+#define CPCAP_BIT_VOL_DAC1 9
+#define CPCAP_BIT_VOL_DAC0 8
+#define CPCAP_BIT_VOL_DAC_LSB_1dB1 7
+#define CPCAP_BIT_VOL_DAC_LSB_1dB0 6
+#define CPCAP_BIT_VOL_CDC3 5
+#define CPCAP_BIT_VOL_CDC2 4
+#define CPCAP_BIT_VOL_CDC1 3
+#define CPCAP_BIT_VOL_CDC0 2
+#define CPCAP_BIT_VOL_CDC_LSB_1dB1 1
+#define CPCAP_BIT_VOL_CDC_LSB_1dB0 0
+
+/* Register 521 CPCAP_REG_RXCOA --- Codec to Output Amp Switches */
+#define CPCAP_BIT_PGA_CDC_EN 10
+#define CPCAP_BIT_CDC_SW 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW 7
+#define CPCAP_BIT_ALEFT_HS_CDC_SW 6
+#define CPCAP_BIT_ARIGHT_HS_CDC_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_CDC_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_CDC_SW 3
+#define CPCAP_BIT_A2_LDSP_L_CDC_SW 2
+#define CPCAP_BIT_A2_LDSP_R_CDC_SW 1
+#define CPCAP_BIT_A1_EAR_CDC_SW 0
+
+/* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */
+#define CPCAP_BIT_PGA_DAC_EN 12
+#define CPCAP_BIT_ST_DAC_SW 11
+#define CPCAP_BIT_MONO_DAC1 10
+#define CPCAP_BIT_MONO_DAC0 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW 7
+#define CPCAP_BIT_ALEFT_HS_DAC_SW 6
+#define CPCAP_BIT_ARIGHT_HS_DAC_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_DAC_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_DAC_SW 3
+#define CPCAP_BIT_A2_LDSP_L_DAC_SW 2
+#define CPCAP_BIT_A2_LDSP_R_DAC_SW 1
+#define CPCAP_BIT_A1_EAR_DAC_SW 0
+
+/* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */
+#define CPCAP_BIT_PGA_EXT_L_EN 14
+#define CPCAP_BIT_PGA_EXT_R_EN 13
+#define CPCAP_BIT_PGA_IN_L_SW 12
+#define CPCAP_BIT_PGA_IN_R_SW 11
+#define CPCAP_BIT_MONO_EXT1 10
+#define CPCAP_BIT_MONO_EXT0 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW 7
+#define CPCAP_BIT_ALEFT_HS_EXT_SW 6
+#define CPCAP_BIT_ARIGHT_HS_EXT_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_EXT_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_EXT_SW 3
+#define CPCAP_BIT_A2_LDSP_L_EXT_SW 2
+#define CPCAP_BIT_A2_LDSP_R_EXT_SW 1
+#define CPCAP_BIT_A1_EAR_EXT_SW 0
+
+/* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */
+#define CPCAP_BIT_NCP_CLK_SYNC 7
+#define CPCAP_BIT_A2_CLK_SYNC 6
+#define CPCAP_BIT_A2_FREE_RUN 5
+#define CPCAP_BIT_A2_CLK2 4
+#define CPCAP_BIT_A2_CLK1 3
+#define CPCAP_BIT_A2_CLK0 2
+#define CPCAP_BIT_A2_CLK_IN 1
+#define CPCAP_BIT_A2_CONFIG 0
+
+#define SLEEP_ACTIVATE_POWER 2
+#define CLOCK_TREE_RESET_TIME 1
+
+/* constants for ST delay workaround */
+#define STM_STDAC_ACTIVATE_RAMP_TIME 1
+#define STM_STDAC_EN_TEST_PRE 0x090C
+#define STM_STDAC_EN_TEST_POST 0x0000
+#define STM_STDAC_EN_ST_TEST1_PRE 0x2400
+#define STM_STDAC_EN_ST_TEST1_POST 0x0400
+
+struct cpcap_reg_info {
+ u16 reg;
+ u16 mask;
+ u16 val;
+};
+
+static const struct cpcap_reg_info cpcap_default_regs[] = {
+ { CPCAP_REG_CC, 0xFFFF, 0x0000 },
+ { CPCAP_REG_CC, 0xFFFF, 0x0000 },
+ { CPCAP_REG_CDI, 0xBFFF, 0x0000 },
+ { CPCAP_REG_SDAC, 0x0FFF, 0x0000 },
+ { CPCAP_REG_SDACDI, 0x3FFF, 0x0000 },
+ { CPCAP_REG_TXI, 0x0FDF, 0x0000 },
+ { CPCAP_REG_TXMP, 0x0FFF, 0x0400 },
+ { CPCAP_REG_RXOA, 0x01FF, 0x0000 },
+ { CPCAP_REG_RXVC, 0xFF3C, 0x0000 },
+ { CPCAP_REG_RXCOA, 0x07FF, 0x0000 },
+ { CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 },
+ { CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 },
+ { CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN),
+ BIT(CPCAP_BIT_A2_FREE_RUN) },
+};
+
+enum cpcap_dai {
+ CPCAP_DAI_HIFI,
+ CPCAP_DAI_VOICE,
+};
+
+struct cpcap_audio {
+ struct snd_soc_codec *codec;
+ struct regmap *regmap;
+
+ u16 vendor;
+
+ int codec_clk_id;
+ int codec_freq;
+ int codec_format;
+};
+
+static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int err = 0;
+
+ /* Only CPCAP from ST requires workaround */
+ if (cpcap->vendor != CPCAP_VENDOR_ST)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+ STM_STDAC_EN_TEST_PRE);
+ if (err)
+ return err;
+ err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+ STM_STDAC_EN_ST_TEST1_PRE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(STM_STDAC_ACTIVATE_RAMP_TIME);
+
+ err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+ STM_STDAC_EN_ST_TEST1_POST);
+ if (err)
+ return err;
+ err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+ STM_STDAC_EN_TEST_POST);
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+/* Capture Gain Control: 0dB to 31dB in 1dB steps */
+static const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+/* Playback Gain Control: -33dB to 12dB in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0);
+
+static const struct snd_kcontrol_new cpcap_snd_controls[] = {
+ /* Playback Gain */
+ SOC_SINGLE_TLV("HiFi Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_DAC0, 0xF, 0, vol_tlv),
+ SOC_SINGLE_TLV("Voice Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_CDC0, 0xF, 0, vol_tlv),
+ SOC_SINGLE_TLV("Ext Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_EXT0, 0xF, 0, vol_tlv),
+
+ /* Capture Gain */
+ SOC_SINGLE_TLV("Mic1 Capture Volume",
+ CPCAP_REG_TXMP, CPCAP_BIT_MIC1_GAIN_0, 0x1F, 0, mic_gain_tlv),
+ SOC_SINGLE_TLV("Mic2 Capture Volume",
+ CPCAP_REG_TXMP, CPCAP_BIT_MIC2_GAIN_0, 0x1F, 0, mic_gain_tlv),
+
+ /* Phase Invert */
+ SOC_SINGLE("Hifi Left Phase Invert Switch",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC0, 1, 0),
+ SOC_SINGLE("Ext Left Phase Invert Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const char * const cpcap_out_mux_texts[] = {
+ "Off", "Voice", "HiFi", "Ext"
+};
+
+static const char * const cpcap_in_right_mux_texts[] = {
+ "Off", "Mic 1", "Headset Mic", "EMU Mic", "Ext Right"
+};
+
+static const char * const cpcap_in_left_mux_texts[] = {
+ "Off", "Mic 2", "Ext Left"
+};
+
+/*
+ * input muxes use unusual register layout, so that we need to use custom
+ * getter/setter methods
+ */
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum,
+ cpcap_in_left_mux_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum,
+ cpcap_in_right_mux_texts);
+
+/*
+ * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA;
+ * even though the register layout makes it look like a mixer, this is a mux.
+ * Enabling multiple inputs will result in no audio being forwarded.
+ */
+static SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);
+
+static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int shift = e->shift_l;
+ int reg_voice, reg_hifi, reg_ext, status;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXCOA, &reg_voice);
+ if (err)
+ return err;
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, &reg_hifi);
+ if (err)
+ return err;
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, &reg_ext);
+ if (err)
+ return err;
+
+ reg_voice = (reg_voice >> shift) & 1;
+ reg_hifi = (reg_hifi >> shift) & 1;
+ reg_ext = (reg_ext >> shift) & 1;
+ status = reg_ext << 2 | reg_hifi << 1 | reg_voice;
+
+ switch (status) {
+ case 0x04:
+ ucontrol->value.enumerated.item[0] = 3;
+ break;
+ case 0x02:
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case 0x01:
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ unsigned int mask = BIT(e->shift_l);
+ u16 reg_voice = 0x00, reg_hifi = 0x00, reg_ext = 0x00;
+ int err;
+
+ switch (muxval) {
+ case 1:
+ reg_voice = mask;
+ break;
+ case 2:
+ reg_hifi = mask;
+ break;
+ case 3:
+ reg_ext = mask;
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+ mask, reg_voice);
+ if (err)
+ return err;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
+ mask, reg_hifi);
+ if (err)
+ return err;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXEPOA,
+ mask, reg_ext);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int regval, mask;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+ if (err)
+ return err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC1_MUX);
+ mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+ switch (regval & mask) {
+ case BIT(CPCAP_BIT_RX_R_ENCODE):
+ ucontrol->value.enumerated.item[0] = 4;
+ break;
+ case BIT(CPCAP_BIT_EMU_MIC_MUX):
+ ucontrol->value.enumerated.item[0] = 3;
+ break;
+ case BIT(CPCAP_BIT_HS_MIC_MUX):
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case BIT(CPCAP_BIT_MIC1_MUX):
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ int regval = 0, mask;
+ int err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC1_MUX);
+ mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+ switch (muxval) {
+ case 1:
+ regval = BIT(CPCAP_BIT_MIC1_MUX);
+ break;
+ case 2:
+ regval = BIT(CPCAP_BIT_HS_MIC_MUX);
+ break;
+ case 3:
+ regval = BIT(CPCAP_BIT_EMU_MIC_MUX);
+ break;
+ case 4:
+ regval = BIT(CPCAP_BIT_RX_R_ENCODE);
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ mask, regval);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int regval, mask;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+ if (err)
+ return err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC2_MUX);
+ mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+ switch (regval & mask) {
+ case BIT(CPCAP_BIT_RX_L_ENCODE):
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case BIT(CPCAP_BIT_MIC2_MUX):
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ int regval = 0, mask;
+ int err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC2_MUX);
+ mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+ switch (muxval) {
+ case 1:
+ regval = BIT(CPCAP_BIT_MIC2_MUX);
+ break;
+ case 2:
+ regval = BIT(CPCAP_BIT_RX_L_ENCODE);
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ mask, regval);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new cpcap_input_left_mux =
+ SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
+ cpcap_input_left_mux_get_enum,
+ cpcap_input_left_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_input_right_mux =
+ SOC_DAPM_ENUM_EXT("Input Right", cpcap_input_right_mux_enum,
+ cpcap_input_right_mux_get_enum,
+ cpcap_input_right_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_left_mux =
+ SOC_DAPM_ENUM_EXT("EMU Left", cpcap_emu_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_right_mux =
+ SOC_DAPM_ENUM_EXT("EMU Right", cpcap_emu_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_left_mux =
+ SOC_DAPM_ENUM_EXT("Headset Left", cpcap_hs_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_right_mux =
+ SOC_DAPM_ENUM_EXT("Headset Right", cpcap_hs_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_left_mux =
+ SOC_DAPM_ENUM_EXT("Line Left", cpcap_line_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_right_mux =
+ SOC_DAPM_ENUM_EXT("Line Right", cpcap_line_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_left_mux =
+ SOC_DAPM_ENUM_EXT("Speaker Left", cpcap_spkr_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_right_mux =
+ SOC_DAPM_ENUM_EXT("Speaker Right", cpcap_spkr_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_earpiece_mux =
+ SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+
+static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("HiFi Mono Playback Switch",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0),
+};
+static const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Ext Mono Playback Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const struct snd_kcontrol_new cpcap_extr_mute_control =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_R_SW, 1, 0);
+static const struct snd_kcontrol_new cpcap_extl_mute_control =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_L_SW, 1, 0);
+
+static const struct snd_kcontrol_new cpcap_voice_loopback =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_TXI, CPCAP_BIT_DLM, 1, 0);
+
+static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = {
+ /* DAIs */
+ SND_SOC_DAPM_AIF_IN("HiFi RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("Voice RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("Voice TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ /* Power Supply */
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VAUDIO", SLEEP_ACTIVATE_POWER, 0),
+
+ /* Highpass Filters */
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter RX",
+ CPCAP_REG_CC, CPCAP_BIT_AUDIHPF_0, 0x3, 0x3, 0x0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter TX",
+ CPCAP_REG_CC, CPCAP_BIT_AUDOHPF_0, 0x3, 0x3, 0x0),
+
+ /* Clocks */
+ SND_SOC_DAPM_SUPPLY("HiFi DAI Clock",
+ CPCAP_REG_SDACDI, CPCAP_BIT_ST_CLK_EN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Voice DAI Clock",
+ CPCAP_REG_CDI, CPCAP_BIT_CDC_CLK_EN, 0, NULL, 0),
+
+ /* Microphone Bias */
+ SND_SOC_DAPM_SUPPLY("MIC1R Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON1R, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC1L Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON1L, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC2 Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON2, 0, NULL, 0),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("MICR"),
+ SND_SOC_DAPM_INPUT("HSMIC"),
+ SND_SOC_DAPM_INPUT("EMUMIC"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("EXTR"),
+ SND_SOC_DAPM_INPUT("EXTL"),
+
+ /* Capture Route */
+ SND_SOC_DAPM_MUX("Right Capture Route",
+ SND_SOC_NOPM, 0, 0, &cpcap_input_right_mux),
+ SND_SOC_DAPM_MUX("Left Capture Route",
+ SND_SOC_NOPM, 0, 0, &cpcap_input_left_mux),
+
+ /* Capture PGAs */
+ SND_SOC_DAPM_PGA("Microphone 1 PGA",
+ CPCAP_REG_TXI, CPCAP_BIT_MIC1_PGA_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Microphone 2 PGA",
+ CPCAP_REG_TXI, CPCAP_BIT_MIC2_PGA_EN, 0, NULL, 0),
+
+ /* ADC */
+ SND_SOC_DAPM_ADC("ADC Right", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_MIC1_CDC_EN, 0),
+ SND_SOC_DAPM_ADC("ADC Left", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_MIC2_CDC_EN, 0),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC_E("DAC HiFi", NULL,
+ CPCAP_REG_SDAC, CPCAP_BIT_ST_DAC_EN, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_DAC_E("DAC Voice", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_CDC_EN_RX, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ /* Playback PGA */
+ SND_SOC_DAPM_PGA("HiFi PGA",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_PGA_DAC_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Voice PGA",
+ CPCAP_REG_RXCOA, CPCAP_BIT_PGA_CDC_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("Ext Right PGA",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_R_EN, 0,
+ NULL, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("Ext Left PGA",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_L_EN, 0,
+ NULL, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ /* Playback Switch */
+ SND_SOC_DAPM_SWITCH("Ext Right Enable", SND_SOC_NOPM, 0, 0,
+ &cpcap_extr_mute_control),
+ SND_SOC_DAPM_SWITCH("Ext Left Enable", SND_SOC_NOPM, 0, 0,
+ &cpcap_extl_mute_control),
+
+ /* Loopback Switch */
+ SND_SOC_DAPM_SWITCH("Voice Loopback", SND_SOC_NOPM, 0, 0,
+ &cpcap_voice_loopback),
+
+ /* Mono Mixer */
+ SOC_MIXER_ARRAY("HiFi Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_hifi_mono_mixer_controls),
+ SOC_MIXER_ARRAY("HiFi Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_hifi_mono_mixer_controls),
+ SOC_MIXER_ARRAY("Ext Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_ext_mono_mixer_controls),
+ SOC_MIXER_ARRAY("Ext Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_ext_mono_mixer_controls),
+
+ /* Output Routes */
+ SND_SOC_DAPM_MUX("Earpiece Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_earpiece_mux),
+ SND_SOC_DAPM_MUX("Speaker Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_speaker_right_mux),
+ SND_SOC_DAPM_MUX("Speaker Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_speaker_left_mux),
+ SND_SOC_DAPM_MUX("Lineout Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_line_right_mux),
+ SND_SOC_DAPM_MUX("Lineout Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_line_left_mux),
+ SND_SOC_DAPM_MUX("Headset Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_hs_right_mux),
+ SND_SOC_DAPM_MUX("Headset Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_hs_left_mux),
+ SND_SOC_DAPM_MUX("EMU Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_emu_right_mux),
+ SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_emu_left_mux),
+
+ /* Output Amplifier */
+ SND_SOC_DAPM_PGA("Earpiece PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_HS_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_HS_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("EMU Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("EMU Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_L_EN, 0, NULL, 0),
+
+ /* Headet Charge Pump */
+ SND_SOC_DAPM_SUPPLY("Headset Charge Pump",
+ CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, 0, NULL, 0),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("EP"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("LINER"),
+ SND_SOC_DAPM_OUTPUT("LINEL"),
+ SND_SOC_DAPM_OUTPUT("HSR"),
+ SND_SOC_DAPM_OUTPUT("HSL"),
+ SND_SOC_DAPM_OUTPUT("EMUR"),
+ SND_SOC_DAPM_OUTPUT("EMUL"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ /* Power Supply */
+ {"HiFi PGA", NULL, "VAUDIO"},
+ {"Voice PGA", NULL, "VAUDIO"},
+ {"Ext Right PGA", NULL, "VAUDIO"},
+ {"Ext Left PGA", NULL, "VAUDIO"},
+ {"Microphone 1 PGA", NULL, "VAUDIO"},
+ {"Microphone 2 PGA", NULL, "VAUDIO"},
+
+ /* Stream -> AIF */
+ {"HiFi RX", NULL, "HiFi Playback"},
+ {"Voice RX", NULL, "Voice Playback"},
+ {"Voice Capture", NULL, "Voice TX"},
+
+ /* AIF clocks */
+ {"HiFi RX", NULL, "HiFi DAI Clock"},
+ {"Voice RX", NULL, "Voice DAI Clock"},
+ {"Voice TX", NULL, "Voice DAI Clock"},
+
+ /* Digital Loopback */
+ {"Voice Loopback", "Switch", "Voice TX"},
+ {"Voice RX", NULL, "Voice Loopback"},
+
+ /* Highpass Filters */
+ {"Highpass Filter RX", NULL, "Voice RX"},
+ {"Voice TX", NULL, "Highpass Filter TX"},
+
+ /* AIF -> DAC mapping */
+ {"DAC HiFi", NULL, "HiFi RX"},
+ {"DAC Voice", NULL, "Highpass Filter RX"},
+
+ /* DAC -> PGA */
+ {"HiFi PGA", NULL, "DAC HiFi"},
+ {"Voice PGA", NULL, "DAC Voice"},
+
+ /* Ext Input -> PGA */
+ {"Ext Right PGA", NULL, "EXTR"},
+ {"Ext Left PGA", NULL, "EXTL"},
+
+ /* Ext PGA -> Ext Playback Switch */
+ {"Ext Right Enable", "Switch", "Ext Right PGA"},
+ {"Ext Left Enable", "Switch", "Ext Left PGA"},
+
+ /* HiFi PGA -> Mono Mixer */
+ {"HiFi Mono Left Mixer", NULL, "HiFi PGA"},
+ {"HiFi Mono Left Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+ {"HiFi Mono Right Mixer", NULL, "HiFi PGA"},
+ {"HiFi Mono Right Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+
+ /* Ext Playback Switch -> Ext Mono Mixer */
+ {"Ext Mono Right Mixer", NULL, "Ext Right Enable"},
+ {"Ext Mono Right Mixer", "Ext Mono Playback Switch", "Ext Left Enable"},
+ {"Ext Mono Left Mixer", NULL, "Ext Left Enable"},
+ {"Ext Mono Left Mixer", "Ext Mono Playback Switch", "Ext Right Enable"},
+
+ /* HiFi Mono Mixer -> Output Route */
+ {"Earpiece Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Speaker Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Speaker Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"Lineout Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Lineout Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"Headset Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Headset Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"EMU Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"EMU Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+
+ /* Voice PGA -> Output Route */
+ {"Earpiece Playback Route", "Voice", "Voice PGA"},
+ {"Speaker Right Playback Route", "Voice", "Voice PGA"},
+ {"Speaker Left Playback Route", "Voice", "Voice PGA"},
+ {"Lineout Right Playback Route", "Voice", "Voice PGA"},
+ {"Lineout Left Playback Route", "Voice", "Voice PGA"},
+ {"Headset Right Playback Route", "Voice", "Voice PGA"},
+ {"Headset Left Playback Route", "Voice", "Voice PGA"},
+ {"EMU Right Playback Route", "Voice", "Voice PGA"},
+ {"EMU Left Playback Route", "Voice", "Voice PGA"},
+
+ /* Ext Mono Mixer -> Output Route */
+ {"Earpiece Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Speaker Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Speaker Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"Lineout Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Lineout Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"Headset Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Headset Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"EMU Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"EMU Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+
+ /* Output Route -> Output Amplifier */
+ {"Earpiece PGA", NULL, "Earpiece Playback Route"},
+ {"Speaker Right PGA", NULL, "Speaker Right Playback Route"},
+ {"Speaker Left PGA", NULL, "Speaker Left Playback Route"},
+ {"Lineout Right PGA", NULL, "Lineout Right Playback Route"},
+ {"Lineout Left PGA", NULL, "Lineout Left Playback Route"},
+ {"Headset Right PGA", NULL, "Headset Right Playback Route"},
+ {"Headset Left PGA", NULL, "Headset Left Playback Route"},
+ {"EMU Right PGA", NULL, "EMU Right Playback Route"},
+ {"EMU Left PGA", NULL, "EMU Left Playback Route"},
+
+ /* Output Amplifier -> Output */
+ {"EP", NULL, "Earpiece PGA"},
+ {"SPKR", NULL, "Speaker Right PGA"},
+ {"SPKL", NULL, "Speaker Left PGA"},
+ {"LINER", NULL, "Lineout Right PGA"},
+ {"LINEL", NULL, "Lineout Left PGA"},
+ {"HSR", NULL, "Headset Right PGA"},
+ {"HSL", NULL, "Headset Left PGA"},
+ {"EMUR", NULL, "EMU Right PGA"},
+ {"EMUL", NULL, "EMU Left PGA"},
+
+ /* Headset Charge Pump -> Headset */
+ {"HSR", NULL, "Headset Charge Pump"},
+ {"HSL", NULL, "Headset Charge Pump"},
+
+ /* Mic -> Mic Route */
+ {"Right Capture Route", "Mic 1", "MICR"},
+ {"Right Capture Route", "Headset Mic", "HSMIC"},
+ {"Right Capture Route", "EMU Mic", "EMUMIC"},
+ {"Right Capture Route", "Ext Right", "EXTR"},
+ {"Left Capture Route", "Mic 2", "MICL"},
+ {"Left Capture Route", "Ext Left", "EXTL"},
+
+ /* Input Route -> Microphone PGA */
+ {"Microphone 1 PGA", NULL, "Right Capture Route"},
+ {"Microphone 2 PGA", NULL, "Left Capture Route"},
+
+ /* Microphone PGA -> ADC */
+ {"ADC Right", NULL, "Microphone 1 PGA"},
+ {"ADC Left", NULL, "Microphone 2 PGA"},
+
+ /* ADC -> Stream */
+ {"Highpass Filter TX", NULL, "ADC Right"},
+ {"Highpass Filter TX", NULL, "ADC Left"},
+
+ /* Mic Bias */
+ {"MICL", NULL, "MIC1L Bias"},
+ {"MICR", NULL, "MIC1R Bias"},
+};
+
+static int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+ int clk_id, int freq)
+{
+ u16 clkfreqreg, clkfreqshift;
+ u16 clkfreqmask, clkfreqval;
+ u16 clkidreg, clkidshift;
+ u16 mask, val;
+ int err;
+
+ switch (dai) {
+ case CPCAP_DAI_HIFI:
+ clkfreqreg = CPCAP_REG_SDAC;
+ clkfreqshift = CPCAP_BIT_ST_DAC_CLK0;
+ clkidreg = CPCAP_REG_SDACDI;
+ clkidshift = CPCAP_BIT_ST_DAC_CLK_IN_SEL;
+ break;
+ case CPCAP_DAI_VOICE:
+ clkfreqreg = CPCAP_REG_CC;
+ clkfreqshift = CPCAP_BIT_CDC_CLK0;
+ clkidreg = CPCAP_REG_CDI;
+ clkidshift = CPCAP_BIT_CLK_IN_SEL;
+ break;
+ default:
+ dev_err(cpcap->codec->dev, "invalid DAI: %d", dai);
+ return -EINVAL;
+ }
+
+ /* setup clk id */
+ if (clk_id < 0 || clk_id > 1) {
+ dev_err(cpcap->codec->dev, "invalid clk id %d", clk_id);
+ return -EINVAL;
+ }
+ err = regmap_update_bits(cpcap->regmap, clkidreg, BIT(clkidshift),
+ clk_id ? BIT(clkidshift) : 0);
+ if (err)
+ return err;
+
+ /* enable PLL for Voice DAI */
+ if (dai == CPCAP_DAI_VOICE) {
+ mask = BIT(CPCAP_BIT_CDC_PLL_SEL);
+ val = BIT(CPCAP_BIT_CDC_PLL_SEL);
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+ mask, val);
+ if (err)
+ return err;
+ }
+
+ /* setup frequency */
+ clkfreqmask = 0x7 << clkfreqshift;
+ switch (freq) {
+ case 15360000:
+ clkfreqval = 0x01 << clkfreqshift;
+ break;
+ case 16800000:
+ clkfreqval = 0x02 << clkfreqshift;
+ break;
+ case 19200000:
+ clkfreqval = 0x03 << clkfreqshift;
+ break;
+ case 26000000:
+ clkfreqval = 0x04 << clkfreqshift;
+ break;
+ case 33600000:
+ clkfreqval = 0x05 << clkfreqshift;
+ break;
+ case 38400000:
+ clkfreqval = 0x06 << clkfreqshift;
+ break;
+ default:
+ dev_err(cpcap->codec->dev, "unsupported freq %u", freq);
+ return -EINVAL;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, clkfreqreg,
+ clkfreqmask, clkfreqval);
+ if (err)
+ return err;
+
+ if (dai == CPCAP_DAI_VOICE) {
+ cpcap->codec_clk_id = clk_id;
+ cpcap->codec_freq = freq;
+ }
+
+ return 0;
+}
+
+static int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+ int samplerate)
+{
+ struct snd_soc_codec *codec = cpcap->codec;
+ u16 sampreg, sampmask, sampshift, sampval, sampreset;
+ int err, sampreadval;
+
+ switch (dai) {
+ case CPCAP_DAI_HIFI:
+ sampreg = CPCAP_REG_SDAC;
+ sampshift = CPCAP_BIT_ST_SR0;
+ sampreset = BIT(CPCAP_BIT_DF_RESET_ST_DAC) |
+ BIT(CPCAP_BIT_ST_CLOCK_TREE_RESET);
+ break;
+ case CPCAP_DAI_VOICE:
+ sampreg = CPCAP_REG_CC;
+ sampshift = CPCAP_BIT_CDC_SR0;
+ sampreset = BIT(CPCAP_BIT_DF_RESET) |
+ BIT(CPCAP_BIT_CDC_CLOCK_TREE_RESET);
+ break;
+ default:
+ dev_err(codec->dev, "invalid DAI: %d", dai);
+ return -EINVAL;
+ }
+
+ sampmask = 0xF << sampshift | sampreset;
+ switch (samplerate) {
+ case 48000:
+ sampval = 0x8 << sampshift;
+ break;
+ case 44100:
+ sampval = 0x7 << sampshift;
+ break;
+ case 32000:
+ sampval = 0x6 << sampshift;
+ break;
+ case 24000:
+ sampval = 0x5 << sampshift;
+ break;
+ case 22050:
+ sampval = 0x4 << sampshift;
+ break;
+ case 16000:
+ sampval = 0x3 << sampshift;
+ break;
+ case 12000:
+ sampval = 0x2 << sampshift;
+ break;
+ case 11025:
+ sampval = 0x1 << sampshift;
+ break;
+ case 8000:
+ sampval = 0x0 << sampshift;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported samplerate %d", samplerate);
+ return -EINVAL;
+ }
+ err = regmap_update_bits(cpcap->regmap, sampreg,
+ sampmask, sampval | sampreset);
+ if (err)
+ return err;
+
+ /* Wait for clock tree reset to complete */
+ mdelay(CLOCK_TREE_RESET_TIME);
+
+ err = regmap_read(cpcap->regmap, sampreg, &sampreadval);
+ if (err)
+ return err;
+
+ if (sampreadval & sampreset) {
+ dev_err(codec->dev, "reset self-clear failed: %04x",
+ sampreadval);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cpcap_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int rate = params_rate(params);
+
+ dev_dbg(codec->dev, "HiFi setup HW params: rate=%d", rate);
+ return cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, rate);
+}
+
+static int cpcap_hifi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+
+ dev_dbg(dev, "HiFi setup sysclk: clk_id=%u, freq=%u", clk_id, freq);
+ return cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, clk_id, freq);
+}
+
+static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+ static const u16 reg = CPCAP_REG_SDACDI;
+ static const u16 mask =
+ BIT(CPCAP_BIT_SMB_ST_DAC) |
+ BIT(CPCAP_BIT_ST_CLK_INV) |
+ BIT(CPCAP_BIT_ST_FS_INV) |
+ BIT(CPCAP_BIT_ST_DIG_AUD_FS0) |
+ BIT(CPCAP_BIT_ST_DIG_AUD_FS1) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT0) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT1) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT2) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT0) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT1) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT2);
+ u16 val = 0x0000;
+
+ dev_dbg(dev, "HiFi setup dai format (%08x)", fmt);
+
+ /*
+ * "HiFi Playback" should always be configured as
+ * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master
+ * SND_SOC_DAIFMT_I2S - I2S mode
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val &= ~BIT(CPCAP_BIT_SMB_ST_DAC);
+ break;
+ default:
+ dev_err(dev, "HiFi dai fmt failed: CPCAP should be master");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= BIT(CPCAP_BIT_ST_FS_INV);
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val |= BIT(CPCAP_BIT_ST_FS_INV);
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ default:
+ dev_err(dev, "HiFi dai fmt failed: unsupported clock invert mode");
+ return -EINVAL;
+ }
+
+ if (val & BIT(CPCAP_BIT_ST_CLK_INV))
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ else
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+ break;
+ default:
+ /* 01 - 4 slots network mode */
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+ val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+ /* L on slot 1 */
+ val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0);
+ break;
+ }
+
+ dev_dbg(dev, "HiFi dai format: val=%04x", val);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg = CPCAP_REG_RXSDOA;
+ static const u16 mask = BIT(CPCAP_BIT_ST_DAC_SW);
+ u16 val;
+
+ if (mute)
+ val = 0;
+ else
+ val = BIT(CPCAP_BIT_ST_DAC_SW);
+
+ dev_dbg(codec->dev, "HiFi mute: %d", mute);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static const struct snd_soc_dai_ops cpcap_dai_hifi_ops = {
+ .hw_params = cpcap_hifi_hw_params,
+ .set_sysclk = cpcap_hifi_set_dai_sysclk,
+ .set_fmt = cpcap_hifi_set_dai_fmt,
+ .digital_mute = cpcap_hifi_set_mute,
+};
+
+static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct device *dev = codec->dev;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg_cdi = CPCAP_REG_CDI;
+ int rate = params_rate(params);
+ int channels = params_channels(params);
+ int direction = substream->stream;
+ u16 val, mask;
+ int err;
+
+ dev_dbg(dev, "Voice setup HW params: rate=%d, direction=%d, chan=%d",
+ rate, direction, channels);
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
+ if (err)
+ return err;
+
+ if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ mask = 0x0000;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT1;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT2;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT0;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT1;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT2;
+ val = 0x0000;
+ if (channels >= 2)
+ val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
+ err = regmap_update_bits(cpcap->regmap, reg_cdi, mask, val);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Voice setup sysclk: clk_id=%u, freq=%u",
+ clk_id, freq);
+ return cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, clk_id, freq);
+}
+
+static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 mask = BIT(CPCAP_BIT_SMB_CDC) |
+ BIT(CPCAP_BIT_CLK_INV) |
+ BIT(CPCAP_BIT_FS_INV) |
+ BIT(CPCAP_BIT_CDC_DIG_AUD_FS0) |
+ BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ u16 val = 0x0000;
+ int err;
+
+ dev_dbg(codec->dev, "Voice setup dai format (%08x)", fmt);
+
+ /*
+ * "Voice Playback" and "Voice Capture" should always be
+ * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm
+ * master
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val &= ~BIT(CPCAP_BIT_SMB_CDC);
+ break;
+ default:
+ dev_err(codec->dev, "Voice dai fmt failed: CPCAP should be the master");
+ val &= ~BIT(CPCAP_BIT_SMB_CDC);
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= BIT(CPCAP_BIT_CLK_INV);
+ val |= BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val |= BIT(CPCAP_BIT_CLK_INV);
+ val &= ~BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ val |= BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ val &= ~BIT(CPCAP_BIT_FS_INV);
+ break;
+ default:
+ dev_err(codec->dev, "Voice dai fmt failed: unsupported clock invert mode");
+ break;
+ }
+
+ if (val & BIT(CPCAP_BIT_CLK_INV))
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ else
+ val |= BIT(CPCAP_BIT_CLK_INV);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* 11 - true I2S mode */
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ break;
+ default:
+ /* 4 timeslots network mode */
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+ val &= ~BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ break;
+ }
+
+ dev_dbg(codec->dev, "Voice dai format: val=%04x", val);
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, mask, val);
+ if (err)
+ return err;
+
+ cpcap->codec_format = val;
+ return 0;
+}
+
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg = CPCAP_REG_RXCOA;
+ static const u16 mask = BIT(CPCAP_BIT_CDC_SW);
+ u16 val;
+
+ if (mute)
+ val = 0;
+ else
+ val = BIT(CPCAP_BIT_CDC_SW);
+
+ dev_dbg(codec->dev, "Voice mute: %d", mute);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+};
+
+static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
+ .hw_params = cpcap_voice_hw_params,
+ .set_sysclk = cpcap_voice_set_dai_sysclk,
+ .set_fmt = cpcap_voice_set_dai_fmt,
+ .digital_mute = cpcap_voice_set_mute,
+};
+
+static struct snd_soc_dai_driver cpcap_dai[] = {
+{
+ .id = 0,
+ .name = "cpcap-hifi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE,
+ },
+ .ops = &cpcap_dai_hifi_ops,
+},
+{
+ .id = 1,
+ .name = "cpcap-voice",
+ .playback = {
+ .stream_name = "Voice Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Voice Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &cpcap_dai_voice_ops,
+},
+};
+
+static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
+{
+ u16 hifi_val, voice_val;
+ u16 hifi_mask = BIT(CPCAP_BIT_DIG_AUD_IN_ST_DAC);
+ u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
+ int err;
+
+
+
+ if (!swap_dai_configuration) {
+ /* Codec on DAI0, HiFi on DAI1 */
+ voice_val = 0;
+ hifi_val = hifi_mask;
+ } else {
+ /* Codec on DAI1, HiFi on DAI0 */
+ voice_val = voice_mask;
+ hifi_val = 0;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+ voice_mask, voice_val);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_SDACDI,
+ hifi_mask, hifi_val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int cpcap_audio_reset(struct snd_soc_codec *codec,
+ bool swap_dai_configuration)
+{
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int i, err = 0;
+
+ dev_dbg(codec->dev, "init audio codec");
+
+ for (i = 0; i < ARRAY_SIZE(cpcap_default_regs); i++) {
+ err = regmap_update_bits(cpcap->regmap,
+ cpcap_default_regs[i].reg,
+ cpcap_default_regs[i].mask,
+ cpcap_default_regs[i].val);
+ if (err)
+ return err;
+ }
+
+ /* setup default settings */
+ err = cpcap_dai_mux(cpcap, swap_dai_configuration);
+ if (err)
+ return err;
+
+ err = cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, 0, 26000000);
+ if (err)
+ return err;
+ err = cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, 0, 26000000);
+ if (err)
+ return err;
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, 48000);
+ if (err)
+ return err;
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, 48000);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int cpcap_soc_probe(struct snd_soc_codec *codec)
+{
+ struct cpcap_audio *cpcap;
+ int err;
+
+ cpcap = devm_kzalloc(codec->dev, sizeof(*cpcap), GFP_KERNEL);
+ if (!cpcap)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, cpcap);
+ cpcap->codec = codec;
+
+ cpcap->regmap = dev_get_regmap(codec->dev->parent, NULL);
+ if (!cpcap->regmap)
+ return -ENODEV;
+ snd_soc_codec_init_regmap(codec, cpcap->regmap);
+
+ err = cpcap_get_vendor(codec->dev, cpcap->regmap, &cpcap->vendor);
+ if (err)
+ return err;
+
+ return cpcap_audio_reset(codec, false);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cpcap = {
+ .probe = cpcap_soc_probe,
+
+ .component_driver = {
+ .controls = cpcap_snd_controls,
+ .num_controls = ARRAY_SIZE(cpcap_snd_controls),
+ .dapm_widgets = cpcap_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cpcap_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
+ },
+};
+
+static int cpcap_codec_probe(struct platform_device *pdev)
+{
+ struct device_node *codec_node =
+ of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+
+ pdev->dev.of_node = codec_node;
+
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cpcap,
+ cpcap_dai, ARRAY_SIZE(cpcap_dai));
+}
+
+static int cpcap_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver cpcap_codec_driver = {
+ .probe = cpcap_codec_probe,
+ .remove = cpcap_codec_remove,
+ .driver = {
+ .name = "cpcap-codec",
+ },
+};
+module_platform_driver(cpcap_codec_driver);
+
+MODULE_ALIAS("platform:cpcap-codec");
+MODULE_DESCRIPTION("ASoC CPCAP codec driver");
+MODULE_AUTHOR("Sebastian Reichel");
+MODULE_LICENSE("GPL v2");
--
2.16.1


2018-02-23 22:25:15

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCHv5 0/5] Motorola Droid 4 Audio Support

* Sebastian Reichel <[email protected]> [180223 20:03]:
> Hi,
>
> This adds audio support to Motorola Droid 4. I dropped the
> regulator from the DT binding as requested by Mark.

Still works for me. Mark, are you happy now with the way
the nodes are set up?

For the binding and driver changes:

Acked-by: Tony Lindgren <[email protected]>

Then I'll be picking up the dts related patches after
no more comments.

Regards,

Tony

2018-02-26 01:38:02

by kernel test robot

[permalink] [raw]
Subject: Re: [alsa-devel] [PATCHv5 2/5] ASoC: codec: cpcap: new codec

Hi Sebastian,

I love your patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on v4.16-rc2 next-20180223]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Sebastian-Reichel/Motorola-Droid-4-Audio-Support/20180226-063007
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> sound/soc/codecs/cpcap.c:1406:54: sparse: restricted snd_pcm_format_t degrades to integer

vim +1406 sound/soc/codecs/cpcap.c

1396
1397 static struct snd_soc_dai_driver cpcap_dai[] = {
1398 {
1399 .id = 0,
1400 .name = "cpcap-hifi",
1401 .playback = {
1402 .stream_name = "HiFi Playback",
1403 .channels_min = 2,
1404 .channels_max = 2,
1405 .rates = SNDRV_PCM_RATE_8000_48000,
> 1406 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE,
1407 },
1408 .ops = &cpcap_dai_hifi_ops,
1409 },
1410 {
1411 .id = 1,
1412 .name = "cpcap-voice",
1413 .playback = {
1414 .stream_name = "Voice Playback",
1415 .channels_min = 1,
1416 .channels_max = 1,
1417 .rates = SNDRV_PCM_RATE_8000_48000,
1418 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1419 },
1420 .capture = {
1421 .stream_name = "Voice Capture",
1422 .channels_min = 1,
1423 .channels_max = 2,
1424 .rates = SNDRV_PCM_RATE_8000_48000,
1425 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1426 },
1427 .ops = &cpcap_dai_voice_ops,
1428 },
1429 };
1430

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

2018-02-26 10:11:35

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCHv5 1/5] dt-bindings: mfd: motorola-cpcap: document audio-codec

On Fri, Feb 23, 2018 at 09:02:50PM +0100, Sebastian Reichel wrote:
> This adds the DT binding for the audio-codec sub-module found
> inside the Motorola CPCAP PMIC.

Acked-by: Mark Brown <[email protected]>


Attachments:
(No filename) (213.00 B)
signature.asc (499.00 B)
Download all attachments

2018-02-27 11:04:44

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCHv5 2/5] ASoC: codec: cpcap: new codec

On Fri, Feb 23, 2018 at 09:02:51PM +0100, Sebastian Reichel wrote:

> + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> + case SND_SOC_DAIFMT_I2S:
> + val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
> + val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
> + break;
> + default:
> + /* 01 - 4 slots network mode */
> + val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
> + val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
> + /* L on slot 1 */
> + val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0);
> + break;
> + }

The default case here is really one specific mode, it looks like it's
either DSP_A or DSP_B. Most likely DSP_A but you should check.
Otherwise this looks good so I'll apply it, please send a followup patch
fixing this to match only the specific mode that's actually supported.


Attachments:
(No filename) (763.00 B)
signature.asc (499.00 B)
Download all attachments

2018-02-28 11:07:54

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: cpcap: new codec" to the asoc tree

The patch

ASoC: cpcap: new codec

has been applied to the asoc tree at

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

From f6cdf2d3445d73f5b27ec8e620b8fe7a1f5c0ea1 Mon Sep 17 00:00:00 2001
From: Sebastian Reichel <[email protected]>
Date: Fri, 23 Feb 2018 21:02:51 +0100
Subject: [PATCH] ASoC: cpcap: new codec

Motorola CPCAP is a PMIC with audio functionality, that can be
found on Motorola Droid 4 and probably a few other phones from
Motorola's Droid series.

The driver has been written from scratch using Motorola's Android
driver, register dumps from running Android and datasheet for NXP
MC13783UG (which is similar to Motorola CPCAP, but not the same).

The chip provides two audio interfaces, that can be muxed to two
different audio codecs. One provides support for stereo output
(named StDAC or HiFi), while the other only provides mono output
(named Voice). Only the Voice codec provides a Capture interface.

Signed-off-by: Sebastian Reichel <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cpcap.c | 1568 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1574 insertions(+)
create mode 100644 sound/soc/codecs/cpcap.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 2b331f7266ab..5bd94841feb6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -408,6 +408,10 @@ config SND_SOC_ALC5632
config SND_SOC_BT_SCO
tristate "Dummy BT SCO codec driver"

+config SND_SOC_CPCAP
+ tristate "Motorola CPCAP codec"
+ depends on MFD_CPCAP
+
config SND_SOC_CQ0093VC
tristate

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index da1571336f1e..2aeee1ba034e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -36,6 +36,7 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-bt-sco-objs := bt-sco.o
+snd-soc-cpcap-objs := cpcap.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs35l33-objs := cs35l33.o
@@ -282,6 +283,7 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
new file mode 100644
index 000000000000..aedb267d4581
--- /dev/null
+++ b/sound/soc/codecs/cpcap.c
@@ -0,0 +1,1568 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC CPCAP codec driver
+ *
+ * Copyright (C) 2017 - 2018 Sebastian Reichel <[email protected]>
+ *
+ * Very loosely based on original driver from Motorola:
+ * Copyright (C) 2007 - 2009 Motorola, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+/* Register 513 CPCAP_REG_CC --- CODEC */
+#define CPCAP_BIT_CDC_CLK2 15
+#define CPCAP_BIT_CDC_CLK1 14
+#define CPCAP_BIT_CDC_CLK0 13
+#define CPCAP_BIT_CDC_SR3 12
+#define CPCAP_BIT_CDC_SR2 11
+#define CPCAP_BIT_CDC_SR1 10
+#define CPCAP_BIT_CDC_SR0 9
+#define CPCAP_BIT_CDC_CLOCK_TREE_RESET 8
+#define CPCAP_BIT_MIC2_CDC_EN 7
+#define CPCAP_BIT_CDC_EN_RX 6
+#define CPCAP_BIT_DF_RESET 5
+#define CPCAP_BIT_MIC1_CDC_EN 4
+#define CPCAP_BIT_AUDOHPF_1 3
+#define CPCAP_BIT_AUDOHPF_0 2
+#define CPCAP_BIT_AUDIHPF_1 1
+#define CPCAP_BIT_AUDIHPF_0 0
+
+/* Register 514 CPCAP_REG_CDI --- CODEC Digital Audio Interface */
+#define CPCAP_BIT_CDC_PLL_SEL 15
+#define CPCAP_BIT_CLK_IN_SEL 13
+#define CPCAP_BIT_DIG_AUD_IN 12
+#define CPCAP_BIT_CDC_CLK_EN 11
+#define CPCAP_BIT_CDC_DIG_AUD_FS1 10
+#define CPCAP_BIT_CDC_DIG_AUD_FS0 9
+#define CPCAP_BIT_MIC2_TIMESLOT2 8
+#define CPCAP_BIT_MIC2_TIMESLOT1 7
+#define CPCAP_BIT_MIC2_TIMESLOT0 6
+#define CPCAP_BIT_MIC1_RX_TIMESLOT2 5
+#define CPCAP_BIT_MIC1_RX_TIMESLOT1 4
+#define CPCAP_BIT_MIC1_RX_TIMESLOT0 3
+#define CPCAP_BIT_FS_INV 2
+#define CPCAP_BIT_CLK_INV 1
+#define CPCAP_BIT_SMB_CDC 0
+
+/* Register 515 CPCAP_REG_SDAC --- Stereo DAC */
+#define CPCAP_BIT_FSYNC_CLK_IN_COMMON 11
+#define CPCAP_BIT_SLAVE_PLL_CLK_INPUT 10
+#define CPCAP_BIT_ST_CLOCK_TREE_RESET 9
+#define CPCAP_BIT_DF_RESET_ST_DAC 8
+#define CPCAP_BIT_ST_SR3 7
+#define CPCAP_BIT_ST_SR2 6
+#define CPCAP_BIT_ST_SR1 5
+#define CPCAP_BIT_ST_SR0 4
+#define CPCAP_BIT_ST_DAC_CLK2 3
+#define CPCAP_BIT_ST_DAC_CLK1 2
+#define CPCAP_BIT_ST_DAC_CLK0 1
+#define CPCAP_BIT_ST_DAC_EN 0
+
+/* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */
+#define CPCAP_BIT_ST_L_TIMESLOT2 13
+#define CPCAP_BIT_ST_L_TIMESLOT1 12
+#define CPCAP_BIT_ST_L_TIMESLOT0 11
+#define CPCAP_BIT_ST_R_TIMESLOT2 10
+#define CPCAP_BIT_ST_R_TIMESLOT1 9
+#define CPCAP_BIT_ST_R_TIMESLOT0 8
+#define CPCAP_BIT_ST_DAC_CLK_IN_SEL 7
+#define CPCAP_BIT_ST_FS_INV 6
+#define CPCAP_BIT_ST_CLK_INV 5
+#define CPCAP_BIT_ST_DIG_AUD_FS1 4
+#define CPCAP_BIT_ST_DIG_AUD_FS0 3
+#define CPCAP_BIT_DIG_AUD_IN_ST_DAC 2
+#define CPCAP_BIT_ST_CLK_EN 1
+#define CPCAP_BIT_SMB_ST_DAC 0
+
+/* Register 517 CPCAP_REG_TXI --- TX Interface */
+#define CPCAP_BIT_PTT_TH 15
+#define CPCAP_BIT_PTT_CMP_EN 14
+#define CPCAP_BIT_HS_ID_TX 13
+#define CPCAP_BIT_MB_ON2 12
+#define CPCAP_BIT_MB_ON1L 11
+#define CPCAP_BIT_MB_ON1R 10
+#define CPCAP_BIT_RX_L_ENCODE 9
+#define CPCAP_BIT_RX_R_ENCODE 8
+#define CPCAP_BIT_MIC2_MUX 7
+#define CPCAP_BIT_MIC2_PGA_EN 6
+#define CPCAP_BIT_CDET_DIS 5
+#define CPCAP_BIT_EMU_MIC_MUX 4
+#define CPCAP_BIT_HS_MIC_MUX 3
+#define CPCAP_BIT_MIC1_MUX 2
+#define CPCAP_BIT_MIC1_PGA_EN 1
+#define CPCAP_BIT_DLM 0
+
+/* Register 518 CPCAP_REG_TXMP --- Mic Gain */
+#define CPCAP_BIT_MB_BIAS_R1 11
+#define CPCAP_BIT_MB_BIAS_R0 10
+#define CPCAP_BIT_MIC2_GAIN_4 9
+#define CPCAP_BIT_MIC2_GAIN_3 8
+#define CPCAP_BIT_MIC2_GAIN_2 7
+#define CPCAP_BIT_MIC2_GAIN_1 6
+#define CPCAP_BIT_MIC2_GAIN_0 5
+#define CPCAP_BIT_MIC1_GAIN_4 4
+#define CPCAP_BIT_MIC1_GAIN_3 3
+#define CPCAP_BIT_MIC1_GAIN_2 2
+#define CPCAP_BIT_MIC1_GAIN_1 1
+#define CPCAP_BIT_MIC1_GAIN_0 0
+
+/* Register 519 CPCAP_REG_RXOA --- RX Output Amplifier */
+#define CPCAP_BIT_UNUSED_519_15 15
+#define CPCAP_BIT_UNUSED_519_14 14
+#define CPCAP_BIT_UNUSED_519_13 13
+#define CPCAP_BIT_STDAC_LOW_PWR_DISABLE 12
+#define CPCAP_BIT_HS_LOW_PWR 11
+#define CPCAP_BIT_HS_ID_RX 10
+#define CPCAP_BIT_ST_HS_CP_EN 9
+#define CPCAP_BIT_EMU_SPKR_R_EN 8
+#define CPCAP_BIT_EMU_SPKR_L_EN 7
+#define CPCAP_BIT_HS_L_EN 6
+#define CPCAP_BIT_HS_R_EN 5
+#define CPCAP_BIT_A4_LINEOUT_L_EN 4
+#define CPCAP_BIT_A4_LINEOUT_R_EN 3
+#define CPCAP_BIT_A2_LDSP_L_EN 2
+#define CPCAP_BIT_A2_LDSP_R_EN 1
+#define CPCAP_BIT_A1_EAR_EN 0
+
+/* Register 520 CPCAP_REG_RXVC --- RX Volume Control */
+#define CPCAP_BIT_VOL_EXT3 15
+#define CPCAP_BIT_VOL_EXT2 14
+#define CPCAP_BIT_VOL_EXT1 13
+#define CPCAP_BIT_VOL_EXT0 12
+#define CPCAP_BIT_VOL_DAC3 11
+#define CPCAP_BIT_VOL_DAC2 10
+#define CPCAP_BIT_VOL_DAC1 9
+#define CPCAP_BIT_VOL_DAC0 8
+#define CPCAP_BIT_VOL_DAC_LSB_1dB1 7
+#define CPCAP_BIT_VOL_DAC_LSB_1dB0 6
+#define CPCAP_BIT_VOL_CDC3 5
+#define CPCAP_BIT_VOL_CDC2 4
+#define CPCAP_BIT_VOL_CDC1 3
+#define CPCAP_BIT_VOL_CDC0 2
+#define CPCAP_BIT_VOL_CDC_LSB_1dB1 1
+#define CPCAP_BIT_VOL_CDC_LSB_1dB0 0
+
+/* Register 521 CPCAP_REG_RXCOA --- Codec to Output Amp Switches */
+#define CPCAP_BIT_PGA_CDC_EN 10
+#define CPCAP_BIT_CDC_SW 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW 7
+#define CPCAP_BIT_ALEFT_HS_CDC_SW 6
+#define CPCAP_BIT_ARIGHT_HS_CDC_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_CDC_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_CDC_SW 3
+#define CPCAP_BIT_A2_LDSP_L_CDC_SW 2
+#define CPCAP_BIT_A2_LDSP_R_CDC_SW 1
+#define CPCAP_BIT_A1_EAR_CDC_SW 0
+
+/* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */
+#define CPCAP_BIT_PGA_DAC_EN 12
+#define CPCAP_BIT_ST_DAC_SW 11
+#define CPCAP_BIT_MONO_DAC1 10
+#define CPCAP_BIT_MONO_DAC0 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW 7
+#define CPCAP_BIT_ALEFT_HS_DAC_SW 6
+#define CPCAP_BIT_ARIGHT_HS_DAC_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_DAC_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_DAC_SW 3
+#define CPCAP_BIT_A2_LDSP_L_DAC_SW 2
+#define CPCAP_BIT_A2_LDSP_R_DAC_SW 1
+#define CPCAP_BIT_A1_EAR_DAC_SW 0
+
+/* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */
+#define CPCAP_BIT_PGA_EXT_L_EN 14
+#define CPCAP_BIT_PGA_EXT_R_EN 13
+#define CPCAP_BIT_PGA_IN_L_SW 12
+#define CPCAP_BIT_PGA_IN_R_SW 11
+#define CPCAP_BIT_MONO_EXT1 10
+#define CPCAP_BIT_MONO_EXT0 9
+#define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW 8
+#define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW 7
+#define CPCAP_BIT_ALEFT_HS_EXT_SW 6
+#define CPCAP_BIT_ARIGHT_HS_EXT_SW 5
+#define CPCAP_BIT_A4_LINEOUT_L_EXT_SW 4
+#define CPCAP_BIT_A4_LINEOUT_R_EXT_SW 3
+#define CPCAP_BIT_A2_LDSP_L_EXT_SW 2
+#define CPCAP_BIT_A2_LDSP_R_EXT_SW 1
+#define CPCAP_BIT_A1_EAR_EXT_SW 0
+
+/* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */
+#define CPCAP_BIT_NCP_CLK_SYNC 7
+#define CPCAP_BIT_A2_CLK_SYNC 6
+#define CPCAP_BIT_A2_FREE_RUN 5
+#define CPCAP_BIT_A2_CLK2 4
+#define CPCAP_BIT_A2_CLK1 3
+#define CPCAP_BIT_A2_CLK0 2
+#define CPCAP_BIT_A2_CLK_IN 1
+#define CPCAP_BIT_A2_CONFIG 0
+
+#define SLEEP_ACTIVATE_POWER 2
+#define CLOCK_TREE_RESET_TIME 1
+
+/* constants for ST delay workaround */
+#define STM_STDAC_ACTIVATE_RAMP_TIME 1
+#define STM_STDAC_EN_TEST_PRE 0x090C
+#define STM_STDAC_EN_TEST_POST 0x0000
+#define STM_STDAC_EN_ST_TEST1_PRE 0x2400
+#define STM_STDAC_EN_ST_TEST1_POST 0x0400
+
+struct cpcap_reg_info {
+ u16 reg;
+ u16 mask;
+ u16 val;
+};
+
+static const struct cpcap_reg_info cpcap_default_regs[] = {
+ { CPCAP_REG_CC, 0xFFFF, 0x0000 },
+ { CPCAP_REG_CC, 0xFFFF, 0x0000 },
+ { CPCAP_REG_CDI, 0xBFFF, 0x0000 },
+ { CPCAP_REG_SDAC, 0x0FFF, 0x0000 },
+ { CPCAP_REG_SDACDI, 0x3FFF, 0x0000 },
+ { CPCAP_REG_TXI, 0x0FDF, 0x0000 },
+ { CPCAP_REG_TXMP, 0x0FFF, 0x0400 },
+ { CPCAP_REG_RXOA, 0x01FF, 0x0000 },
+ { CPCAP_REG_RXVC, 0xFF3C, 0x0000 },
+ { CPCAP_REG_RXCOA, 0x07FF, 0x0000 },
+ { CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 },
+ { CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 },
+ { CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN),
+ BIT(CPCAP_BIT_A2_FREE_RUN) },
+};
+
+enum cpcap_dai {
+ CPCAP_DAI_HIFI,
+ CPCAP_DAI_VOICE,
+};
+
+struct cpcap_audio {
+ struct snd_soc_codec *codec;
+ struct regmap *regmap;
+
+ u16 vendor;
+
+ int codec_clk_id;
+ int codec_freq;
+ int codec_format;
+};
+
+static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int err = 0;
+
+ /* Only CPCAP from ST requires workaround */
+ if (cpcap->vendor != CPCAP_VENDOR_ST)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+ STM_STDAC_EN_TEST_PRE);
+ if (err)
+ return err;
+ err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+ STM_STDAC_EN_ST_TEST1_PRE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(STM_STDAC_ACTIVATE_RAMP_TIME);
+
+ err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+ STM_STDAC_EN_ST_TEST1_POST);
+ if (err)
+ return err;
+ err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+ STM_STDAC_EN_TEST_POST);
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+/* Capture Gain Control: 0dB to 31dB in 1dB steps */
+static const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+/* Playback Gain Control: -33dB to 12dB in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0);
+
+static const struct snd_kcontrol_new cpcap_snd_controls[] = {
+ /* Playback Gain */
+ SOC_SINGLE_TLV("HiFi Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_DAC0, 0xF, 0, vol_tlv),
+ SOC_SINGLE_TLV("Voice Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_CDC0, 0xF, 0, vol_tlv),
+ SOC_SINGLE_TLV("Ext Playback Volume",
+ CPCAP_REG_RXVC, CPCAP_BIT_VOL_EXT0, 0xF, 0, vol_tlv),
+
+ /* Capture Gain */
+ SOC_SINGLE_TLV("Mic1 Capture Volume",
+ CPCAP_REG_TXMP, CPCAP_BIT_MIC1_GAIN_0, 0x1F, 0, mic_gain_tlv),
+ SOC_SINGLE_TLV("Mic2 Capture Volume",
+ CPCAP_REG_TXMP, CPCAP_BIT_MIC2_GAIN_0, 0x1F, 0, mic_gain_tlv),
+
+ /* Phase Invert */
+ SOC_SINGLE("Hifi Left Phase Invert Switch",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC0, 1, 0),
+ SOC_SINGLE("Ext Left Phase Invert Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const char * const cpcap_out_mux_texts[] = {
+ "Off", "Voice", "HiFi", "Ext"
+};
+
+static const char * const cpcap_in_right_mux_texts[] = {
+ "Off", "Mic 1", "Headset Mic", "EMU Mic", "Ext Right"
+};
+
+static const char * const cpcap_in_left_mux_texts[] = {
+ "Off", "Mic 2", "Ext Left"
+};
+
+/*
+ * input muxes use unusual register layout, so that we need to use custom
+ * getter/setter methods
+ */
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum,
+ cpcap_in_left_mux_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum,
+ cpcap_in_right_mux_texts);
+
+/*
+ * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA;
+ * even though the register layout makes it look like a mixer, this is a mux.
+ * Enabling multiple inputs will result in no audio being forwarded.
+ */
+static SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);
+
+static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int shift = e->shift_l;
+ int reg_voice, reg_hifi, reg_ext, status;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXCOA, &reg_voice);
+ if (err)
+ return err;
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, &reg_hifi);
+ if (err)
+ return err;
+ err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, &reg_ext);
+ if (err)
+ return err;
+
+ reg_voice = (reg_voice >> shift) & 1;
+ reg_hifi = (reg_hifi >> shift) & 1;
+ reg_ext = (reg_ext >> shift) & 1;
+ status = reg_ext << 2 | reg_hifi << 1 | reg_voice;
+
+ switch (status) {
+ case 0x04:
+ ucontrol->value.enumerated.item[0] = 3;
+ break;
+ case 0x02:
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case 0x01:
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ unsigned int mask = BIT(e->shift_l);
+ u16 reg_voice = 0x00, reg_hifi = 0x00, reg_ext = 0x00;
+ int err;
+
+ switch (muxval) {
+ case 1:
+ reg_voice = mask;
+ break;
+ case 2:
+ reg_hifi = mask;
+ break;
+ case 3:
+ reg_ext = mask;
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+ mask, reg_voice);
+ if (err)
+ return err;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
+ mask, reg_hifi);
+ if (err)
+ return err;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXEPOA,
+ mask, reg_ext);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int regval, mask;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+ if (err)
+ return err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC1_MUX);
+ mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+ switch (regval & mask) {
+ case BIT(CPCAP_BIT_RX_R_ENCODE):
+ ucontrol->value.enumerated.item[0] = 4;
+ break;
+ case BIT(CPCAP_BIT_EMU_MIC_MUX):
+ ucontrol->value.enumerated.item[0] = 3;
+ break;
+ case BIT(CPCAP_BIT_HS_MIC_MUX):
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case BIT(CPCAP_BIT_MIC1_MUX):
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ int regval = 0, mask;
+ int err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC1_MUX);
+ mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+ mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+ switch (muxval) {
+ case 1:
+ regval = BIT(CPCAP_BIT_MIC1_MUX);
+ break;
+ case 2:
+ regval = BIT(CPCAP_BIT_HS_MIC_MUX);
+ break;
+ case 3:
+ regval = BIT(CPCAP_BIT_EMU_MIC_MUX);
+ break;
+ case 4:
+ regval = BIT(CPCAP_BIT_RX_R_ENCODE);
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ mask, regval);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int regval, mask;
+ int err;
+
+ err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+ if (err)
+ return err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC2_MUX);
+ mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+ switch (regval & mask) {
+ case BIT(CPCAP_BIT_RX_L_ENCODE):
+ ucontrol->value.enumerated.item[0] = 2;
+ break;
+ case BIT(CPCAP_BIT_MIC2_MUX):
+ ucontrol->value.enumerated.item[0] = 1;
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ int regval = 0, mask;
+ int err;
+
+ mask = 0;
+ mask |= BIT(CPCAP_BIT_MIC2_MUX);
+ mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+ switch (muxval) {
+ case 1:
+ regval = BIT(CPCAP_BIT_MIC2_MUX);
+ break;
+ case 2:
+ regval = BIT(CPCAP_BIT_RX_L_ENCODE);
+ break;
+ default:
+ break;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ mask, regval);
+ if (err)
+ return err;
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new cpcap_input_left_mux =
+ SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
+ cpcap_input_left_mux_get_enum,
+ cpcap_input_left_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_input_right_mux =
+ SOC_DAPM_ENUM_EXT("Input Right", cpcap_input_right_mux_enum,
+ cpcap_input_right_mux_get_enum,
+ cpcap_input_right_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_left_mux =
+ SOC_DAPM_ENUM_EXT("EMU Left", cpcap_emu_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_right_mux =
+ SOC_DAPM_ENUM_EXT("EMU Right", cpcap_emu_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_left_mux =
+ SOC_DAPM_ENUM_EXT("Headset Left", cpcap_hs_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_right_mux =
+ SOC_DAPM_ENUM_EXT("Headset Right", cpcap_hs_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_left_mux =
+ SOC_DAPM_ENUM_EXT("Line Left", cpcap_line_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_right_mux =
+ SOC_DAPM_ENUM_EXT("Line Right", cpcap_line_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_left_mux =
+ SOC_DAPM_ENUM_EXT("Speaker Left", cpcap_spkr_l_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_right_mux =
+ SOC_DAPM_ENUM_EXT("Speaker Right", cpcap_spkr_r_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_earpiece_mux =
+ SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum,
+ cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+
+static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("HiFi Mono Playback Switch",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0),
+};
+static const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Ext Mono Playback Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const struct snd_kcontrol_new cpcap_extr_mute_control =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_R_SW, 1, 0);
+static const struct snd_kcontrol_new cpcap_extl_mute_control =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_L_SW, 1, 0);
+
+static const struct snd_kcontrol_new cpcap_voice_loopback =
+ SOC_DAPM_SINGLE("Switch",
+ CPCAP_REG_TXI, CPCAP_BIT_DLM, 1, 0);
+
+static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = {
+ /* DAIs */
+ SND_SOC_DAPM_AIF_IN("HiFi RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("Voice RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("Voice TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ /* Power Supply */
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VAUDIO", SLEEP_ACTIVATE_POWER, 0),
+
+ /* Highpass Filters */
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter RX",
+ CPCAP_REG_CC, CPCAP_BIT_AUDIHPF_0, 0x3, 0x3, 0x0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter TX",
+ CPCAP_REG_CC, CPCAP_BIT_AUDOHPF_0, 0x3, 0x3, 0x0),
+
+ /* Clocks */
+ SND_SOC_DAPM_SUPPLY("HiFi DAI Clock",
+ CPCAP_REG_SDACDI, CPCAP_BIT_ST_CLK_EN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Voice DAI Clock",
+ CPCAP_REG_CDI, CPCAP_BIT_CDC_CLK_EN, 0, NULL, 0),
+
+ /* Microphone Bias */
+ SND_SOC_DAPM_SUPPLY("MIC1R Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON1R, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC1L Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON1L, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC2 Bias",
+ CPCAP_REG_TXI, CPCAP_BIT_MB_ON2, 0, NULL, 0),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("MICR"),
+ SND_SOC_DAPM_INPUT("HSMIC"),
+ SND_SOC_DAPM_INPUT("EMUMIC"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("EXTR"),
+ SND_SOC_DAPM_INPUT("EXTL"),
+
+ /* Capture Route */
+ SND_SOC_DAPM_MUX("Right Capture Route",
+ SND_SOC_NOPM, 0, 0, &cpcap_input_right_mux),
+ SND_SOC_DAPM_MUX("Left Capture Route",
+ SND_SOC_NOPM, 0, 0, &cpcap_input_left_mux),
+
+ /* Capture PGAs */
+ SND_SOC_DAPM_PGA("Microphone 1 PGA",
+ CPCAP_REG_TXI, CPCAP_BIT_MIC1_PGA_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Microphone 2 PGA",
+ CPCAP_REG_TXI, CPCAP_BIT_MIC2_PGA_EN, 0, NULL, 0),
+
+ /* ADC */
+ SND_SOC_DAPM_ADC("ADC Right", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_MIC1_CDC_EN, 0),
+ SND_SOC_DAPM_ADC("ADC Left", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_MIC2_CDC_EN, 0),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC_E("DAC HiFi", NULL,
+ CPCAP_REG_SDAC, CPCAP_BIT_ST_DAC_EN, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_DAC_E("DAC Voice", NULL,
+ CPCAP_REG_CC, CPCAP_BIT_CDC_EN_RX, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ /* Playback PGA */
+ SND_SOC_DAPM_PGA("HiFi PGA",
+ CPCAP_REG_RXSDOA, CPCAP_BIT_PGA_DAC_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Voice PGA",
+ CPCAP_REG_RXCOA, CPCAP_BIT_PGA_CDC_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("Ext Right PGA",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_R_EN, 0,
+ NULL, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("Ext Left PGA",
+ CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_L_EN, 0,
+ NULL, 0,
+ cpcap_st_workaround,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ /* Playback Switch */
+ SND_SOC_DAPM_SWITCH("Ext Right Enable", SND_SOC_NOPM, 0, 0,
+ &cpcap_extr_mute_control),
+ SND_SOC_DAPM_SWITCH("Ext Left Enable", SND_SOC_NOPM, 0, 0,
+ &cpcap_extl_mute_control),
+
+ /* Loopback Switch */
+ SND_SOC_DAPM_SWITCH("Voice Loopback", SND_SOC_NOPM, 0, 0,
+ &cpcap_voice_loopback),
+
+ /* Mono Mixer */
+ SOC_MIXER_ARRAY("HiFi Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_hifi_mono_mixer_controls),
+ SOC_MIXER_ARRAY("HiFi Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_hifi_mono_mixer_controls),
+ SOC_MIXER_ARRAY("Ext Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_ext_mono_mixer_controls),
+ SOC_MIXER_ARRAY("Ext Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+ cpcap_ext_mono_mixer_controls),
+
+ /* Output Routes */
+ SND_SOC_DAPM_MUX("Earpiece Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_earpiece_mux),
+ SND_SOC_DAPM_MUX("Speaker Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_speaker_right_mux),
+ SND_SOC_DAPM_MUX("Speaker Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_speaker_left_mux),
+ SND_SOC_DAPM_MUX("Lineout Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_line_right_mux),
+ SND_SOC_DAPM_MUX("Lineout Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_line_left_mux),
+ SND_SOC_DAPM_MUX("Headset Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_hs_right_mux),
+ SND_SOC_DAPM_MUX("Headset Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_hs_left_mux),
+ SND_SOC_DAPM_MUX("EMU Right Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_emu_right_mux),
+ SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0,
+ &cpcap_emu_left_mux),
+
+ /* Output Amplifier */
+ SND_SOC_DAPM_PGA("Earpiece PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_HS_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_HS_L_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("EMU Right PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_R_EN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("EMU Left PGA",
+ CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_L_EN, 0, NULL, 0),
+
+ /* Headet Charge Pump */
+ SND_SOC_DAPM_SUPPLY("Headset Charge Pump",
+ CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, 0, NULL, 0),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("EP"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("LINER"),
+ SND_SOC_DAPM_OUTPUT("LINEL"),
+ SND_SOC_DAPM_OUTPUT("HSR"),
+ SND_SOC_DAPM_OUTPUT("HSL"),
+ SND_SOC_DAPM_OUTPUT("EMUR"),
+ SND_SOC_DAPM_OUTPUT("EMUL"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ /* Power Supply */
+ {"HiFi PGA", NULL, "VAUDIO"},
+ {"Voice PGA", NULL, "VAUDIO"},
+ {"Ext Right PGA", NULL, "VAUDIO"},
+ {"Ext Left PGA", NULL, "VAUDIO"},
+ {"Microphone 1 PGA", NULL, "VAUDIO"},
+ {"Microphone 2 PGA", NULL, "VAUDIO"},
+
+ /* Stream -> AIF */
+ {"HiFi RX", NULL, "HiFi Playback"},
+ {"Voice RX", NULL, "Voice Playback"},
+ {"Voice Capture", NULL, "Voice TX"},
+
+ /* AIF clocks */
+ {"HiFi RX", NULL, "HiFi DAI Clock"},
+ {"Voice RX", NULL, "Voice DAI Clock"},
+ {"Voice TX", NULL, "Voice DAI Clock"},
+
+ /* Digital Loopback */
+ {"Voice Loopback", "Switch", "Voice TX"},
+ {"Voice RX", NULL, "Voice Loopback"},
+
+ /* Highpass Filters */
+ {"Highpass Filter RX", NULL, "Voice RX"},
+ {"Voice TX", NULL, "Highpass Filter TX"},
+
+ /* AIF -> DAC mapping */
+ {"DAC HiFi", NULL, "HiFi RX"},
+ {"DAC Voice", NULL, "Highpass Filter RX"},
+
+ /* DAC -> PGA */
+ {"HiFi PGA", NULL, "DAC HiFi"},
+ {"Voice PGA", NULL, "DAC Voice"},
+
+ /* Ext Input -> PGA */
+ {"Ext Right PGA", NULL, "EXTR"},
+ {"Ext Left PGA", NULL, "EXTL"},
+
+ /* Ext PGA -> Ext Playback Switch */
+ {"Ext Right Enable", "Switch", "Ext Right PGA"},
+ {"Ext Left Enable", "Switch", "Ext Left PGA"},
+
+ /* HiFi PGA -> Mono Mixer */
+ {"HiFi Mono Left Mixer", NULL, "HiFi PGA"},
+ {"HiFi Mono Left Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+ {"HiFi Mono Right Mixer", NULL, "HiFi PGA"},
+ {"HiFi Mono Right Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+
+ /* Ext Playback Switch -> Ext Mono Mixer */
+ {"Ext Mono Right Mixer", NULL, "Ext Right Enable"},
+ {"Ext Mono Right Mixer", "Ext Mono Playback Switch", "Ext Left Enable"},
+ {"Ext Mono Left Mixer", NULL, "Ext Left Enable"},
+ {"Ext Mono Left Mixer", "Ext Mono Playback Switch", "Ext Right Enable"},
+
+ /* HiFi Mono Mixer -> Output Route */
+ {"Earpiece Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Speaker Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Speaker Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"Lineout Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Lineout Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"Headset Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"Headset Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+ {"EMU Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+ {"EMU Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+
+ /* Voice PGA -> Output Route */
+ {"Earpiece Playback Route", "Voice", "Voice PGA"},
+ {"Speaker Right Playback Route", "Voice", "Voice PGA"},
+ {"Speaker Left Playback Route", "Voice", "Voice PGA"},
+ {"Lineout Right Playback Route", "Voice", "Voice PGA"},
+ {"Lineout Left Playback Route", "Voice", "Voice PGA"},
+ {"Headset Right Playback Route", "Voice", "Voice PGA"},
+ {"Headset Left Playback Route", "Voice", "Voice PGA"},
+ {"EMU Right Playback Route", "Voice", "Voice PGA"},
+ {"EMU Left Playback Route", "Voice", "Voice PGA"},
+
+ /* Ext Mono Mixer -> Output Route */
+ {"Earpiece Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Speaker Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Speaker Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"Lineout Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Lineout Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"Headset Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"Headset Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+ {"EMU Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+ {"EMU Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+
+ /* Output Route -> Output Amplifier */
+ {"Earpiece PGA", NULL, "Earpiece Playback Route"},
+ {"Speaker Right PGA", NULL, "Speaker Right Playback Route"},
+ {"Speaker Left PGA", NULL, "Speaker Left Playback Route"},
+ {"Lineout Right PGA", NULL, "Lineout Right Playback Route"},
+ {"Lineout Left PGA", NULL, "Lineout Left Playback Route"},
+ {"Headset Right PGA", NULL, "Headset Right Playback Route"},
+ {"Headset Left PGA", NULL, "Headset Left Playback Route"},
+ {"EMU Right PGA", NULL, "EMU Right Playback Route"},
+ {"EMU Left PGA", NULL, "EMU Left Playback Route"},
+
+ /* Output Amplifier -> Output */
+ {"EP", NULL, "Earpiece PGA"},
+ {"SPKR", NULL, "Speaker Right PGA"},
+ {"SPKL", NULL, "Speaker Left PGA"},
+ {"LINER", NULL, "Lineout Right PGA"},
+ {"LINEL", NULL, "Lineout Left PGA"},
+ {"HSR", NULL, "Headset Right PGA"},
+ {"HSL", NULL, "Headset Left PGA"},
+ {"EMUR", NULL, "EMU Right PGA"},
+ {"EMUL", NULL, "EMU Left PGA"},
+
+ /* Headset Charge Pump -> Headset */
+ {"HSR", NULL, "Headset Charge Pump"},
+ {"HSL", NULL, "Headset Charge Pump"},
+
+ /* Mic -> Mic Route */
+ {"Right Capture Route", "Mic 1", "MICR"},
+ {"Right Capture Route", "Headset Mic", "HSMIC"},
+ {"Right Capture Route", "EMU Mic", "EMUMIC"},
+ {"Right Capture Route", "Ext Right", "EXTR"},
+ {"Left Capture Route", "Mic 2", "MICL"},
+ {"Left Capture Route", "Ext Left", "EXTL"},
+
+ /* Input Route -> Microphone PGA */
+ {"Microphone 1 PGA", NULL, "Right Capture Route"},
+ {"Microphone 2 PGA", NULL, "Left Capture Route"},
+
+ /* Microphone PGA -> ADC */
+ {"ADC Right", NULL, "Microphone 1 PGA"},
+ {"ADC Left", NULL, "Microphone 2 PGA"},
+
+ /* ADC -> Stream */
+ {"Highpass Filter TX", NULL, "ADC Right"},
+ {"Highpass Filter TX", NULL, "ADC Left"},
+
+ /* Mic Bias */
+ {"MICL", NULL, "MIC1L Bias"},
+ {"MICR", NULL, "MIC1R Bias"},
+};
+
+static int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+ int clk_id, int freq)
+{
+ u16 clkfreqreg, clkfreqshift;
+ u16 clkfreqmask, clkfreqval;
+ u16 clkidreg, clkidshift;
+ u16 mask, val;
+ int err;
+
+ switch (dai) {
+ case CPCAP_DAI_HIFI:
+ clkfreqreg = CPCAP_REG_SDAC;
+ clkfreqshift = CPCAP_BIT_ST_DAC_CLK0;
+ clkidreg = CPCAP_REG_SDACDI;
+ clkidshift = CPCAP_BIT_ST_DAC_CLK_IN_SEL;
+ break;
+ case CPCAP_DAI_VOICE:
+ clkfreqreg = CPCAP_REG_CC;
+ clkfreqshift = CPCAP_BIT_CDC_CLK0;
+ clkidreg = CPCAP_REG_CDI;
+ clkidshift = CPCAP_BIT_CLK_IN_SEL;
+ break;
+ default:
+ dev_err(cpcap->codec->dev, "invalid DAI: %d", dai);
+ return -EINVAL;
+ }
+
+ /* setup clk id */
+ if (clk_id < 0 || clk_id > 1) {
+ dev_err(cpcap->codec->dev, "invalid clk id %d", clk_id);
+ return -EINVAL;
+ }
+ err = regmap_update_bits(cpcap->regmap, clkidreg, BIT(clkidshift),
+ clk_id ? BIT(clkidshift) : 0);
+ if (err)
+ return err;
+
+ /* enable PLL for Voice DAI */
+ if (dai == CPCAP_DAI_VOICE) {
+ mask = BIT(CPCAP_BIT_CDC_PLL_SEL);
+ val = BIT(CPCAP_BIT_CDC_PLL_SEL);
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+ mask, val);
+ if (err)
+ return err;
+ }
+
+ /* setup frequency */
+ clkfreqmask = 0x7 << clkfreqshift;
+ switch (freq) {
+ case 15360000:
+ clkfreqval = 0x01 << clkfreqshift;
+ break;
+ case 16800000:
+ clkfreqval = 0x02 << clkfreqshift;
+ break;
+ case 19200000:
+ clkfreqval = 0x03 << clkfreqshift;
+ break;
+ case 26000000:
+ clkfreqval = 0x04 << clkfreqshift;
+ break;
+ case 33600000:
+ clkfreqval = 0x05 << clkfreqshift;
+ break;
+ case 38400000:
+ clkfreqval = 0x06 << clkfreqshift;
+ break;
+ default:
+ dev_err(cpcap->codec->dev, "unsupported freq %u", freq);
+ return -EINVAL;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, clkfreqreg,
+ clkfreqmask, clkfreqval);
+ if (err)
+ return err;
+
+ if (dai == CPCAP_DAI_VOICE) {
+ cpcap->codec_clk_id = clk_id;
+ cpcap->codec_freq = freq;
+ }
+
+ return 0;
+}
+
+static int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+ int samplerate)
+{
+ struct snd_soc_codec *codec = cpcap->codec;
+ u16 sampreg, sampmask, sampshift, sampval, sampreset;
+ int err, sampreadval;
+
+ switch (dai) {
+ case CPCAP_DAI_HIFI:
+ sampreg = CPCAP_REG_SDAC;
+ sampshift = CPCAP_BIT_ST_SR0;
+ sampreset = BIT(CPCAP_BIT_DF_RESET_ST_DAC) |
+ BIT(CPCAP_BIT_ST_CLOCK_TREE_RESET);
+ break;
+ case CPCAP_DAI_VOICE:
+ sampreg = CPCAP_REG_CC;
+ sampshift = CPCAP_BIT_CDC_SR0;
+ sampreset = BIT(CPCAP_BIT_DF_RESET) |
+ BIT(CPCAP_BIT_CDC_CLOCK_TREE_RESET);
+ break;
+ default:
+ dev_err(codec->dev, "invalid DAI: %d", dai);
+ return -EINVAL;
+ }
+
+ sampmask = 0xF << sampshift | sampreset;
+ switch (samplerate) {
+ case 48000:
+ sampval = 0x8 << sampshift;
+ break;
+ case 44100:
+ sampval = 0x7 << sampshift;
+ break;
+ case 32000:
+ sampval = 0x6 << sampshift;
+ break;
+ case 24000:
+ sampval = 0x5 << sampshift;
+ break;
+ case 22050:
+ sampval = 0x4 << sampshift;
+ break;
+ case 16000:
+ sampval = 0x3 << sampshift;
+ break;
+ case 12000:
+ sampval = 0x2 << sampshift;
+ break;
+ case 11025:
+ sampval = 0x1 << sampshift;
+ break;
+ case 8000:
+ sampval = 0x0 << sampshift;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported samplerate %d", samplerate);
+ return -EINVAL;
+ }
+ err = regmap_update_bits(cpcap->regmap, sampreg,
+ sampmask, sampval | sampreset);
+ if (err)
+ return err;
+
+ /* Wait for clock tree reset to complete */
+ mdelay(CLOCK_TREE_RESET_TIME);
+
+ err = regmap_read(cpcap->regmap, sampreg, &sampreadval);
+ if (err)
+ return err;
+
+ if (sampreadval & sampreset) {
+ dev_err(codec->dev, "reset self-clear failed: %04x",
+ sampreadval);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cpcap_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int rate = params_rate(params);
+
+ dev_dbg(codec->dev, "HiFi setup HW params: rate=%d", rate);
+ return cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, rate);
+}
+
+static int cpcap_hifi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+
+ dev_dbg(dev, "HiFi setup sysclk: clk_id=%u, freq=%u", clk_id, freq);
+ return cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, clk_id, freq);
+}
+
+static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct device *dev = codec->dev;
+ static const u16 reg = CPCAP_REG_SDACDI;
+ static const u16 mask =
+ BIT(CPCAP_BIT_SMB_ST_DAC) |
+ BIT(CPCAP_BIT_ST_CLK_INV) |
+ BIT(CPCAP_BIT_ST_FS_INV) |
+ BIT(CPCAP_BIT_ST_DIG_AUD_FS0) |
+ BIT(CPCAP_BIT_ST_DIG_AUD_FS1) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT0) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT1) |
+ BIT(CPCAP_BIT_ST_L_TIMESLOT2) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT0) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT1) |
+ BIT(CPCAP_BIT_ST_R_TIMESLOT2);
+ u16 val = 0x0000;
+
+ dev_dbg(dev, "HiFi setup dai format (%08x)", fmt);
+
+ /*
+ * "HiFi Playback" should always be configured as
+ * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master
+ * SND_SOC_DAIFMT_I2S - I2S mode
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val &= ~BIT(CPCAP_BIT_SMB_ST_DAC);
+ break;
+ default:
+ dev_err(dev, "HiFi dai fmt failed: CPCAP should be master");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= BIT(CPCAP_BIT_ST_FS_INV);
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val |= BIT(CPCAP_BIT_ST_FS_INV);
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ break;
+ default:
+ dev_err(dev, "HiFi dai fmt failed: unsupported clock invert mode");
+ return -EINVAL;
+ }
+
+ if (val & BIT(CPCAP_BIT_ST_CLK_INV))
+ val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+ else
+ val |= BIT(CPCAP_BIT_ST_CLK_INV);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+ break;
+ default:
+ /* 01 - 4 slots network mode */
+ val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+ val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+ /* L on slot 1 */
+ val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0);
+ break;
+ }
+
+ dev_dbg(dev, "HiFi dai format: val=%04x", val);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg = CPCAP_REG_RXSDOA;
+ static const u16 mask = BIT(CPCAP_BIT_ST_DAC_SW);
+ u16 val;
+
+ if (mute)
+ val = 0;
+ else
+ val = BIT(CPCAP_BIT_ST_DAC_SW);
+
+ dev_dbg(codec->dev, "HiFi mute: %d", mute);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static const struct snd_soc_dai_ops cpcap_dai_hifi_ops = {
+ .hw_params = cpcap_hifi_hw_params,
+ .set_sysclk = cpcap_hifi_set_dai_sysclk,
+ .set_fmt = cpcap_hifi_set_dai_fmt,
+ .digital_mute = cpcap_hifi_set_mute,
+};
+
+static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct device *dev = codec->dev;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg_cdi = CPCAP_REG_CDI;
+ int rate = params_rate(params);
+ int channels = params_channels(params);
+ int direction = substream->stream;
+ u16 val, mask;
+ int err;
+
+ dev_dbg(dev, "Voice setup HW params: rate=%d, direction=%d, chan=%d",
+ rate, direction, channels);
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
+ if (err)
+ return err;
+
+ if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ mask = 0x0000;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT1;
+ mask |= CPCAP_BIT_MIC1_RX_TIMESLOT2;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT0;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT1;
+ mask |= CPCAP_BIT_MIC2_TIMESLOT2;
+ val = 0x0000;
+ if (channels >= 2)
+ val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
+ err = regmap_update_bits(cpcap->regmap, reg_cdi, mask, val);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Voice setup sysclk: clk_id=%u, freq=%u",
+ clk_id, freq);
+ return cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, clk_id, freq);
+}
+
+static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 mask = BIT(CPCAP_BIT_SMB_CDC) |
+ BIT(CPCAP_BIT_CLK_INV) |
+ BIT(CPCAP_BIT_FS_INV) |
+ BIT(CPCAP_BIT_CDC_DIG_AUD_FS0) |
+ BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ u16 val = 0x0000;
+ int err;
+
+ dev_dbg(codec->dev, "Voice setup dai format (%08x)", fmt);
+
+ /*
+ * "Voice Playback" and "Voice Capture" should always be
+ * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm
+ * master
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val &= ~BIT(CPCAP_BIT_SMB_CDC);
+ break;
+ default:
+ dev_err(codec->dev, "Voice dai fmt failed: CPCAP should be the master");
+ val &= ~BIT(CPCAP_BIT_SMB_CDC);
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= BIT(CPCAP_BIT_CLK_INV);
+ val |= BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val |= BIT(CPCAP_BIT_CLK_INV);
+ val &= ~BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ val |= BIT(CPCAP_BIT_FS_INV);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ val &= ~BIT(CPCAP_BIT_FS_INV);
+ break;
+ default:
+ dev_err(codec->dev, "Voice dai fmt failed: unsupported clock invert mode");
+ break;
+ }
+
+ if (val & BIT(CPCAP_BIT_CLK_INV))
+ val &= ~BIT(CPCAP_BIT_CLK_INV);
+ else
+ val |= BIT(CPCAP_BIT_CLK_INV);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* 11 - true I2S mode */
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ break;
+ default:
+ /* 4 timeslots network mode */
+ val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+ val &= ~BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+ break;
+ }
+
+ dev_dbg(codec->dev, "Voice dai format: val=%04x", val);
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, mask, val);
+ if (err)
+ return err;
+
+ cpcap->codec_format = val;
+ return 0;
+}
+
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg = CPCAP_REG_RXCOA;
+ static const u16 mask = BIT(CPCAP_BIT_CDC_SW);
+ u16 val;
+
+ if (mute)
+ val = 0;
+ else
+ val = BIT(CPCAP_BIT_CDC_SW);
+
+ dev_dbg(codec->dev, "Voice mute: %d", mute);
+ return regmap_update_bits(cpcap->regmap, reg, mask, val);
+};
+
+static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
+ .hw_params = cpcap_voice_hw_params,
+ .set_sysclk = cpcap_voice_set_dai_sysclk,
+ .set_fmt = cpcap_voice_set_dai_fmt,
+ .digital_mute = cpcap_voice_set_mute,
+};
+
+static struct snd_soc_dai_driver cpcap_dai[] = {
+{
+ .id = 0,
+ .name = "cpcap-hifi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE,
+ },
+ .ops = &cpcap_dai_hifi_ops,
+},
+{
+ .id = 1,
+ .name = "cpcap-voice",
+ .playback = {
+ .stream_name = "Voice Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Voice Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &cpcap_dai_voice_ops,
+},
+};
+
+static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
+{
+ u16 hifi_val, voice_val;
+ u16 hifi_mask = BIT(CPCAP_BIT_DIG_AUD_IN_ST_DAC);
+ u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
+ int err;
+
+
+
+ if (!swap_dai_configuration) {
+ /* Codec on DAI0, HiFi on DAI1 */
+ voice_val = 0;
+ hifi_val = hifi_mask;
+ } else {
+ /* Codec on DAI1, HiFi on DAI0 */
+ voice_val = voice_mask;
+ hifi_val = 0;
+ }
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+ voice_mask, voice_val);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_SDACDI,
+ hifi_mask, hifi_val);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int cpcap_audio_reset(struct snd_soc_codec *codec,
+ bool swap_dai_configuration)
+{
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ int i, err = 0;
+
+ dev_dbg(codec->dev, "init audio codec");
+
+ for (i = 0; i < ARRAY_SIZE(cpcap_default_regs); i++) {
+ err = regmap_update_bits(cpcap->regmap,
+ cpcap_default_regs[i].reg,
+ cpcap_default_regs[i].mask,
+ cpcap_default_regs[i].val);
+ if (err)
+ return err;
+ }
+
+ /* setup default settings */
+ err = cpcap_dai_mux(cpcap, swap_dai_configuration);
+ if (err)
+ return err;
+
+ err = cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, 0, 26000000);
+ if (err)
+ return err;
+ err = cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, 0, 26000000);
+ if (err)
+ return err;
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, 48000);
+ if (err)
+ return err;
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, 48000);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int cpcap_soc_probe(struct snd_soc_codec *codec)
+{
+ struct cpcap_audio *cpcap;
+ int err;
+
+ cpcap = devm_kzalloc(codec->dev, sizeof(*cpcap), GFP_KERNEL);
+ if (!cpcap)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, cpcap);
+ cpcap->codec = codec;
+
+ cpcap->regmap = dev_get_regmap(codec->dev->parent, NULL);
+ if (!cpcap->regmap)
+ return -ENODEV;
+ snd_soc_codec_init_regmap(codec, cpcap->regmap);
+
+ err = cpcap_get_vendor(codec->dev, cpcap->regmap, &cpcap->vendor);
+ if (err)
+ return err;
+
+ return cpcap_audio_reset(codec, false);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cpcap = {
+ .probe = cpcap_soc_probe,
+
+ .component_driver = {
+ .controls = cpcap_snd_controls,
+ .num_controls = ARRAY_SIZE(cpcap_snd_controls),
+ .dapm_widgets = cpcap_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cpcap_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
+ },
+};
+
+static int cpcap_codec_probe(struct platform_device *pdev)
+{
+ struct device_node *codec_node =
+ of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+
+ pdev->dev.of_node = codec_node;
+
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cpcap,
+ cpcap_dai, ARRAY_SIZE(cpcap_dai));
+}
+
+static int cpcap_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver cpcap_codec_driver = {
+ .probe = cpcap_codec_probe,
+ .remove = cpcap_codec_remove,
+ .driver = {
+ .name = "cpcap-codec",
+ },
+};
+module_platform_driver(cpcap_codec_driver);
+
+MODULE_ALIAS("platform:cpcap-codec");
+MODULE_DESCRIPTION("ASoC CPCAP codec driver");
+MODULE_AUTHOR("Sebastian Reichel");
+MODULE_LICENSE("GPL v2");
--
2.16.1


2018-03-02 21:55:03

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCHv5 0/5] Motorola Droid 4 Audio Support

* Tony Lindgren <[email protected]> [180223 22:25]:
> Then I'll be picking up the dts related patches after
> no more comments.

Applying patches 4/5 and 5/5 into omap-for-v4.17/dt thanks.

Tony

2018-03-03 03:22:31

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCHv5 1/5] dt-bindings: mfd: motorola-cpcap: document audio-codec

On Fri, Feb 23, 2018 at 09:02:50PM +0100, Sebastian Reichel wrote:
> This adds the DT binding for the audio-codec sub-module found
> inside the Motorola CPCAP PMIC.
>
> Signed-off-by: Sebastian Reichel <[email protected]>
> ---
> .../devicetree/bindings/mfd/motorola-cpcap.txt | 42 ++++++++++++++++++++++
> 1 file changed, 42 insertions(+)

Reviewed-by: Rob Herring <[email protected]>

2018-03-07 16:34:00

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 1/5] dt-bindings: mfd: motorola-cpcap: document audio-codec

On Fri, 23 Feb 2018, Sebastian Reichel wrote:

> This adds the DT binding for the audio-codec sub-module found
> inside the Motorola CPCAP PMIC.
>
> Signed-off-by: Sebastian Reichel <[email protected]>
> ---
> .../devicetree/bindings/mfd/motorola-cpcap.txt | 42 ++++++++++++++++++++++
> 1 file changed, 42 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt b/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
> index 15bc885f9df4..82c3a7140660 100644
> --- a/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
> +++ b/Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
> @@ -12,6 +12,30 @@ Required properties:
> - spi-max-frequency : Typically set to 3000000
> - spi-cs-high : SPI chip select direction
>
> +Optional subnodes:
> +
> +The sub-functions of CPCAP get their own node with their own compatible values,
> +which are described in the following files:
> +
> +- Documentation/devicetree/bindings/power/supply/cpcap-battery.txt
> +- Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
> +- Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
> +- Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt
> +- Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
> +- Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
> +- Documentation/devicetree/bindings/leds/leds-cpcap.txt
> +- Documentation/devicetree/bindings/iio/adc/cpcap-adc.txt

Nit: Best to use relative path names here (hint: DT docs might not
live in there kernel forever).

Other than that:

For my own reference:
Acked-for-MFD-by: Lee Jones <[email protected]>

--
Lee Jones
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-07 16:34:16

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Fri, 23 Feb 2018, Sebastian Reichel wrote:

> From: Sebastian Reichel <[email protected]>
>
> Add support for the audio-codec node by converting from
> devm_of_platform_populate() to devm_mfd_add_devices().
>
> Signed-off-by: Sebastian Reichel <[email protected]>
> ---
> drivers/mfd/motorola-cpcap.c | 51 +++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 50 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
> index d2cc1eabac05..f6c79a4ccb55 100644
> --- a/drivers/mfd/motorola-cpcap.c
> +++ b/drivers/mfd/motorola-cpcap.c
> @@ -18,6 +18,7 @@
> #include <linux/regmap.h>
> #include <linux/sysfs.h>
>
> +#include <linux/mfd/core.h>
> #include <linux/mfd/motorola-cpcap.h>
> #include <linux/spi/spi.h>
>
> @@ -216,6 +217,53 @@ static const struct regmap_config cpcap_regmap_config = {
> .val_format_endian = REGMAP_ENDIAN_LITTLE,
> };
>
> +static const struct mfd_cell cpcap_mfd_devices[] = {
> + {
> + .name = "cpcap_adc",
> + .of_compatible = "motorola,mapphone-cpcap-adc",
> + }, {
> + .name = "cpcap_battery",
> + .of_compatible = "motorola,cpcap-battery",
> + }, {
> + .name = "cpcap-charger",
> + .of_compatible = "motorola,mapphone-cpcap-charger",
> + }, {
> + .name = "cpcap-regulator",
> + .of_compatible = "motorola,mapphone-cpcap-regulator",
> + }, {
> + .name = "cpcap-rtc",
> + .of_compatible = "motorola,cpcap-rtc",
> + }, {
> + .name = "cpcap-pwrbutton",
> + .of_compatible = "motorola,cpcap-pwrbutton",
> + }, {
> + .name = "cpcap-usb-phy",
> + .of_compatible = "motorola,mapphone-cpcap-usb-phy",
> + }, {
> + .name = "cpcap-led",
> + .id = 0,
> + .of_compatible = "motorola,cpcap-led-red",
> + }, {
> + .name = "cpcap-led",
> + .id = 1,
> + .of_compatible = "motorola,cpcap-led-green",
> + }, {
> + .name = "cpcap-led",
> + .id = 2,
> + .of_compatible = "motorola,cpcap-led-blue",
> + }, {
> + .name = "cpcap-led",
> + .id = 3,
> + .of_compatible = "motorola,cpcap-led-adl",
> + }, {
> + .name = "cpcap-led",
> + .id = 4,
> + .of_compatible = "motorola,cpcap-led-cp",
> + }, {
> + .name = "cpcap-codec",
> + }
> +};

With none of the entries containing platform_data /me wonders why you
can't still use devm_of_platform_populate()?

> static int cpcap_probe(struct spi_device *spi)
> {
> const struct of_device_id *match;
> @@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
> if (ret)
> return ret;
>
> - return devm_of_platform_populate(&cpcap->spi->dev);
> + return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
> + ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
> }
>
> static struct spi_driver cpcap_driver = {

--
Lee Jones
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-08 09:48:02

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

Hi Lee,

On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > +static const struct mfd_cell cpcap_mfd_devices[] = {

[...]

> > + }, {
> > + .name = "cpcap-led",
> > + .id = 4,
> > + .of_compatible = "motorola,cpcap-led-cp",
> > + }, {
> > + .name = "cpcap-codec",
> > + }
> > +};
>
> With none of the entries containing platform_data /me wonders why you
> can't still use devm_of_platform_populate()?

Because devm_of_platform_populate works with compatible properties and
cpcap-codec does not have one after I removed it for Mark.

-- Sebastian

> > static int cpcap_probe(struct spi_device *spi)
> > {
> > const struct of_device_id *match;
> > @@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
> > if (ret)
> > return ret;
> >
> > - return devm_of_platform_populate(&cpcap->spi->dev);
> > + return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
> > + ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
> > }
> >
> > static struct spi_driver cpcap_driver = {
>
> --
> Lee Jones
> Linaro Services Technical Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog


Attachments:
(No filename) (1.26 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-08 09:55:27

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > +static const struct mfd_cell cpcap_mfd_devices[] = {
>
> [...]
>
> > > + }, {
> > > + .name = "cpcap-led",
> > > + .id = 4,
> > > + .of_compatible = "motorola,cpcap-led-cp",
> > > + }, {
> > > + .name = "cpcap-codec",
> > > + }
> > > +};
> >
> > With none of the entries containing platform_data /me wonders why you
> > can't still use devm_of_platform_populate()?
>
> Because devm_of_platform_populate works with compatible properties and
> cpcap-codec does not have one after I removed it for Mark.

Sorry, I missed that conversation. Why was it removed?

> > > static int cpcap_probe(struct spi_device *spi)
> > > {
> > > const struct of_device_id *match;
> > > @@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
> > > if (ret)
> > > return ret;
> > >
> > > - return devm_of_platform_populate(&cpcap->spi->dev);
> > > + return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
> > > + ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
> > > }
> > >
> > > static struct spi_driver cpcap_driver = {
> >



--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-08 10:29:07

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

Hi,

On Thu, Mar 08, 2018 at 09:53:15AM +0000, Lee Jones wrote:
> On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> > On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > > +static const struct mfd_cell cpcap_mfd_devices[] = {
> >
> > [...]
> >
> > > > + }, {
> > > > + .name = "cpcap-led",
> > > > + .id = 4,
> > > > + .of_compatible = "motorola,cpcap-led-cp",
> > > > + }, {
> > > > + .name = "cpcap-codec",
> > > > + }
> > > > +};
> > >
> > > With none of the entries containing platform_data /me wonders why you
> > > can't still use devm_of_platform_populate()?
> >
> > Because devm_of_platform_populate works with compatible properties and
> > cpcap-codec does not have one after I removed it for Mark.
>
> Sorry, I missed that conversation. Why was it removed?

I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
to have it in the DT ABI.

-- Sebastian

> > > > static int cpcap_probe(struct spi_device *spi)
> > > > {
> > > > const struct of_device_id *match;
> > > > @@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
> > > > if (ret)
> > > > return ret;
> > > >
> > > > - return devm_of_platform_populate(&cpcap->spi->dev);
> > > > + return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
> > > > + ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
> > > > }
> > > >
> > > > static struct spi_driver cpcap_driver = {
> > >
>
>
>
> --
> Lee Jones [李琼斯]
> Linaro Services Technical Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog


Attachments:
(No filename) (1.67 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-08 10:49:58

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> On Thu, Mar 08, 2018 at 09:53:15AM +0000, Lee Jones wrote:
> > On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> > > On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > > > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > > > +static const struct mfd_cell cpcap_mfd_devices[] = {
> > >
> > > [...]
> > >
> > > > > + }, {
> > > > > + .name = "cpcap-led",
> > > > > + .id = 4,
> > > > > + .of_compatible = "motorola,cpcap-led-cp",
> > > > > + }, {
> > > > > + .name = "cpcap-codec",
> > > > > + }
> > > > > +};
> > > >
> > > > With none of the entries containing platform_data /me wonders why you
> > > > can't still use devm_of_platform_populate()?
> > >
> > > Because devm_of_platform_populate works with compatible properties and
> > > cpcap-codec does not have one after I removed it for Mark.
> >
> > Sorry, I missed that conversation. Why was it removed?
>
> I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
> to have it in the DT ABI.

Right, but why? Is it not a hardware device? I think converting from
devm_of_platform_populate() for one sub-device is a bit drastic.

--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-08 11:26:56

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Thu, Mar 08, 2018 at 10:48:31AM +0000, Lee Jones wrote:
> On Thu, 08 Mar 2018, Sebastian Reichel wrote:

> > I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
> > to have it in the DT ABI.

> Right, but why? Is it not a hardware device? I think converting from
> devm_of_platform_populate() for one sub-device is a bit drastic.

It's not a separate physical device or IP and doesn't exist outside of
the MFD, it's just how Linux is currently choosing to divide up the chip
right now but that's totally open to change even in future versions of
Linux. Clocks are a big issue with audio stuff, right now sections of
the clock tree get handled in the CODEC driver but we're going to want
to push them out to a clock driver so we're not reimplementing handling
for clocks.


Attachments:
(No filename) (809.00 B)
signature.asc (499.00 B)
Download all attachments

2018-03-08 12:55:23

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

Hi,

On Thu, Mar 08, 2018 at 10:48:31AM +0000, Lee Jones wrote:
> On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> > On Thu, Mar 08, 2018 at 09:53:15AM +0000, Lee Jones wrote:
> > > On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> > > > On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > > > > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > > > > +static const struct mfd_cell cpcap_mfd_devices[] = {
> > > >
> > > > [...]
> > > >
> > > > > > + }, {
> > > > > > + .name = "cpcap-led",
> > > > > > + .id = 4,
> > > > > > + .of_compatible = "motorola,cpcap-led-cp",
> > > > > > + }, {
> > > > > > + .name = "cpcap-codec",
> > > > > > + }
> > > > > > +};
> > > > >
> > > > > With none of the entries containing platform_data /me wonders why you
> > > > > can't still use devm_of_platform_populate()?
> > > >
> > > > Because devm_of_platform_populate works with compatible properties and
> > > > cpcap-codec does not have one after I removed it for Mark.
> > >
> > > Sorry, I missed that conversation. Why was it removed?
> >
> > I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
> > to have it in the DT ABI.
>
> Right, but why? Is it not a hardware device? I think converting from
> devm_of_platform_populate() for one sub-device is a bit drastic.

This must be answered by Mark. Personally I think it makes more sense
to have the compatible, since all other cpcap sub-devices have them
and it should be consistent IMHO. I changed it to avoid bikeshedding.

The previous discussion was here: https://patchwork.kernel.org/patch/10220035/

-- Sebastian


Attachments:
(No filename) (1.63 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-08 17:11:51

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

* Sebastian Reichel <[email protected]> [180308 09:47]:
> Hi Lee,
>
> On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > +static const struct mfd_cell cpcap_mfd_devices[] = {
>
> [...]
>
> > > + }, {
> > > + .name = "cpcap-led",
> > > + .id = 4,
> > > + .of_compatible = "motorola,cpcap-led-cp",
> > > + }, {
> > > + .name = "cpcap-codec",
> > > + }
> > > +};
> >
> > With none of the entries containing platform_data /me wonders why you
> > can't still use devm_of_platform_populate()?
>
> Because devm_of_platform_populate works with compatible properties and
> cpcap-codec does not have one after I removed it for Mark.

How about keep devm_of_platform_populate() for the ones that
already have compatible. Then add a table entry for cpcap-codec
only and call devm_mfd_add_devices()?

Regards,

Tony

2018-03-09 08:35:35

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Thu, 08 Mar 2018, Mark Brown wrote:

> On Thu, Mar 08, 2018 at 10:48:31AM +0000, Lee Jones wrote:
> > On Thu, 08 Mar 2018, Sebastian Reichel wrote:
>
> > > I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
> > > to have it in the DT ABI.
>
> > Right, but why? Is it not a hardware device? I think converting from
> > devm_of_platform_populate() for one sub-device is a bit drastic.
>
> It's not a separate physical device or IP and doesn't exist outside of
> the MFD, it's just how Linux is currently choosing to divide up the chip
> right now but that's totally open to change even in future versions of
> Linux. Clocks are a big issue with audio stuff, right now sections of
> the clock tree get handled in the CODEC driver but we're going to want
> to push them out to a clock driver so we're not reimplementing handling
> for clocks.

How is the CODEC controlled? Does it have its own registers? I guess
by "it's not a separate device or IP" you mean that it doesn't. But
that begs the question, how does this then device differ from all the
other devices (adc, battery, charger, regulator, rtc, pwrbutton,
usb-phy and led)?

I'm asking, not to be awkward, but to avoid 50 lines of potentially
unnecessary static code. If this is a real (sub-)device, even if it's
part of a larger, single device (MFD) then there is no reason why it
can't be represented as a single, albeit empty node.

--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-09 11:21:24

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Fri, Mar 09, 2018 at 08:34:14AM +0000, Lee Jones wrote:
> On Thu, 08 Mar 2018, Mark Brown wrote:
>
> > On Thu, Mar 08, 2018 at 10:48:31AM +0000, Lee Jones wrote:
> > > On Thu, 08 Mar 2018, Sebastian Reichel wrote:
> >
> > > > I had it in PATCHv1-PATCHv4. It was removed, since Mark didn't want
> > > > to have it in the DT ABI.
> >
> > > Right, but why? Is it not a hardware device? I think converting from
> > > devm_of_platform_populate() for one sub-device is a bit drastic.
> >
> > It's not a separate physical device or IP and doesn't exist outside of
> > the MFD, it's just how Linux is currently choosing to divide up the chip
> > right now but that's totally open to change even in future versions of
> > Linux. Clocks are a big issue with audio stuff, right now sections of
> > the clock tree get handled in the CODEC driver but we're going to want
> > to push them out to a clock driver so we're not reimplementing handling
> > for clocks.
>
> How is the CODEC controlled? Does it have its own registers? I guess
> by "it's not a separate device or IP" you mean that it doesn't. But
> that begs the question, how does this then device differ from all the
> other devices (adc, battery, charger, regulator, rtc, pwrbutton,
> usb-phy and led)?

The audio codec goes from register 0x0800 - 0x0844, with the next
register being defined @ 0x0a00. So it definetly has its own register
range. I should note though, that 0x0800 is the audio regulator
control. In Linux we handle this one in the regulator driver instead
of in the audio driver. But this is mostly hidden in DT (the voltage
ranges for VAUDIO are described in the regulator node now).

> I'm asking, not to be awkward, but to avoid 50 lines of potentially
> unnecessary static code. If this is a real (sub-)device, even if it's
> part of a larger, single device (MFD) then there is no reason why it
> can't be represented as a single, albeit empty node.

We still have the node, so that it can be used with the ASoC graph
binding. It just has no compatible value. Instead it is identified
by the node's name.

-- Sebastian


Attachments:
(No filename) (2.10 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-09 11:30:26

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

Hi,

On Thu, Mar 08, 2018 at 09:07:36AM -0800, Tony Lindgren wrote:
> * Sebastian Reichel <[email protected]> [180308 09:47]:
> > Hi Lee,
> >
> > On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > > +static const struct mfd_cell cpcap_mfd_devices[] = {
> >
> > [...]
> >
> > > > + }, {
> > > > + .name = "cpcap-led",
> > > > + .id = 4,
> > > > + .of_compatible = "motorola,cpcap-led-cp",
> > > > + }, {
> > > > + .name = "cpcap-codec",
> > > > + }
> > > > +};
> > >
> > > With none of the entries containing platform_data /me wonders why you
> > > can't still use devm_of_platform_populate()?
> >
> > Because devm_of_platform_populate works with compatible properties and
> > cpcap-codec does not have one after I removed it for Mark.
>
> How about keep devm_of_platform_populate() for the ones that
> already have compatible. Then add a table entry for cpcap-codec
> only and call devm_mfd_add_devices()?

This should work. I think it makes sense to wait for Rob Herring's
feedback on the binding. My understanding is, that he has the last
word on binding questions and I would like to avoid changing this
back and forth.

-- Sebastian


Attachments:
(No filename) (1.26 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-09 12:41:37

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Fri, Mar 09, 2018 at 08:34:14AM +0000, Lee Jones wrote:
> On Thu, 08 Mar 2018, Mark Brown wrote:

> > Linux. Clocks are a big issue with audio stuff, right now sections of
> > the clock tree get handled in the CODEC driver but we're going to want
> > to push them out to a clock driver so we're not reimplementing handling
> > for clocks.

> How is the CODEC controlled? Does it have its own registers? I guess
> by "it's not a separate device or IP" you mean that it doesn't. But
> that begs the question, how does this then device differ from all the
> other devices (adc, battery, charger, regulator, rtc, pwrbutton,
> usb-phy and led)?

I'm not convinced that this is a particularly good idea for the other
functions but anyway... the big thing here is that in these devices the
CODEC is generally not the level that the IP is created at, it's a
collection of interlinked IPs which usually includes not only audio
stuff but also some clocking stuff. The repeatable blocks that could
get reused independently are generally a level down from the CODEC
level, for example if you look at something like wm8994 there's a couple
of identical FLL IPs which could make sense to enumerate individually in
the DT. The top level generally doesn't get reused and is purely an
encoding of what Linux is currently doing.

Regulators have a bit of this going on as well - you can see it in the
wm831x series of drivers where the devices have a bunch of consistently
defined regulators that are laid out in various configurations so we
have one platform device per physical regulator (not sure if that ever
got converted to DT).

Most of the other things you list are more at the level of the FLL where
it's a single thing doing a single task that is likely to be repeated
somewhere else as a block so there's more sense, though how often that
actually happens can be questionable.

> I'm asking, not to be awkward, but to avoid 50 lines of potentially
> unnecessary static code. If this is a real (sub-)device, even if it's
> part of a larger, single device (MFD) then there is no reason why it
> can't be represented as a single, albeit empty node.

It never used to be that complicated to define MFD functions? It was a
data table and then a function call to register the table en masse.
Certainly not anything it's worth defining an ABI to avoid.


Attachments:
(No filename) (2.34 kB)
signature.asc (499.00 B)
Download all attachments

2018-03-09 15:13:10

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

* Mark Brown <[email protected]> [180309 12:41]:
> On Fri, Mar 09, 2018 at 08:34:14AM +0000, Lee Jones wrote:
> > On Thu, 08 Mar 2018, Mark Brown wrote:
>
> > > Linux. Clocks are a big issue with audio stuff, right now sections of
> > > the clock tree get handled in the CODEC driver but we're going to want
> > > to push them out to a clock driver so we're not reimplementing handling
> > > for clocks.
>
> > How is the CODEC controlled? Does it have its own registers? I guess
> > by "it's not a separate device or IP" you mean that it doesn't. But
> > that begs the question, how does this then device differ from all the
> > other devices (adc, battery, charger, regulator, rtc, pwrbutton,
> > usb-phy and led)?
>
> I'm not convinced that this is a particularly good idea for the other
> functions but anyway... the big thing here is that in these devices the
> CODEC is generally not the level that the IP is created at, it's a
> collection of interlinked IPs which usually includes not only audio
> stuff but also some clocking stuff. The repeatable blocks that could
> get reused independently are generally a level down from the CODEC
> level, for example if you look at something like wm8994 there's a couple
> of identical FLL IPs which could make sense to enumerate individually in
> the DT. The top level generally doesn't get reused and is purely an
> encoding of what Linux is currently doing.

It seems that most of the components in the PMICs are just standard
components packed into the PMIC with a control interface provided
over I2C or SPI.

So using compatible for things like ADC, RTC and so on makes sense
if eventually figure out which ones are shared across various
drivers.

Sounds like audio is a bit more fuzzy like Mark describes above.
And by not using a compatible for audio we can have things working
while not establishing and ABI for something that might change
in the future.

Regards,

Tony

2018-03-09 16:49:45

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

Hi,

On Fri, Mar 09, 2018 at 07:11:53AM -0800, Tony Lindgren wrote:
> * Mark Brown <[email protected]> [180309 12:41]:
> > On Fri, Mar 09, 2018 at 08:34:14AM +0000, Lee Jones wrote:
> > > On Thu, 08 Mar 2018, Mark Brown wrote:
> >
> > > > Linux. Clocks are a big issue with audio stuff, right now sections of
> > > > the clock tree get handled in the CODEC driver but we're going to want
> > > > to push them out to a clock driver so we're not reimplementing handling
> > > > for clocks.
> >
> > > How is the CODEC controlled? Does it have its own registers? I guess
> > > by "it's not a separate device or IP" you mean that it doesn't. But
> > > that begs the question, how does this then device differ from all the
> > > other devices (adc, battery, charger, regulator, rtc, pwrbutton,
> > > usb-phy and led)?
> >
> > I'm not convinced that this is a particularly good idea for the other
> > functions but anyway... the big thing here is that in these devices the
> > CODEC is generally not the level that the IP is created at, it's a
> > collection of interlinked IPs which usually includes not only audio
> > stuff but also some clocking stuff. The repeatable blocks that could
> > get reused independently are generally a level down from the CODEC
> > level, for example if you look at something like wm8994 there's a couple
> > of identical FLL IPs which could make sense to enumerate individually in
> > the DT. The top level generally doesn't get reused and is purely an
> > encoding of what Linux is currently doing.
>
> It seems that most of the components in the PMICs are just standard
> components packed into the PMIC with a control interface provided
> over I2C or SPI.
>
> So using compatible for things like ADC, RTC and so on makes sense
> if eventually figure out which ones are shared across various
> drivers.
>
> Sounds like audio is a bit more fuzzy like Mark describes above.
> And by not using a compatible for audio we can have things working
> while not establishing and ABI for something that might change
> in the future.

I would agree, if there was no ABI now, but we still have the
ABI. Instead of specifying the compatible property, we now need
to specify what the node name should look like (see my binding
update). That's just a different ABI.

-- Sebastian


Attachments:
(No filename) (2.30 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-12 09:10:17

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCHv5 3/5] mfd: motorola-cpcap: Add audio-codec support

On Fri, 09 Mar 2018, Sebastian Reichel wrote:

> Hi,
>
> On Thu, Mar 08, 2018 at 09:07:36AM -0800, Tony Lindgren wrote:
> > * Sebastian Reichel <[email protected]> [180308 09:47]:
> > > Hi Lee,
> > >
> > > On Wed, Mar 07, 2018 at 04:32:11PM +0000, Lee Jones wrote:
> > > > On Fri, 23 Feb 2018, Sebastian Reichel wrote:
> > > > > +static const struct mfd_cell cpcap_mfd_devices[] = {
> > >
> > > [...]
> > >
> > > > > + }, {
> > > > > + .name = "cpcap-led",
> > > > > + .id = 4,
> > > > > + .of_compatible = "motorola,cpcap-led-cp",
> > > > > + }, {
> > > > > + .name = "cpcap-codec",
> > > > > + }
> > > > > +};
> > > >
> > > > With none of the entries containing platform_data /me wonders why you
> > > > can't still use devm_of_platform_populate()?
> > >
> > > Because devm_of_platform_populate works with compatible properties and
> > > cpcap-codec does not have one after I removed it for Mark.
> >
> > How about keep devm_of_platform_populate() for the ones that
> > already have compatible. Then add a table entry for cpcap-codec
> > only and call devm_mfd_add_devices()?
>
> This should work. I think it makes sense to wait for Rob Herring's
> feedback on the binding. My understanding is, that he has the last
> word on binding questions and I would like to avoid changing this
> back and forth.

I've been avoiding mix-and-matching mfd_*() and of_platform_*() APIs,
else it gets too confusing for new developers.

*If* you make the switch to mfd_*() APIs (not preferable), then I
would like to see of_platform_*() removed.

--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2018-03-22 20:49:22

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> Add sound support to Motorola Droid 4 using simple-soundcard
> and CPCAP's audio codec. This does not yet correctly represent
> the whole audio routing, since McBSP3 is also connected to
> Bluetooth and MDM6600 modem (and probably also 4G modem).
> These extra DAI links are not yet supported and have not been
> tested.

I applied the series on top v4.16-rc5, but I can't seem to get it
to work:

root@devuan:/sys/devices/platform/usb-phy@1# cat /proc/asound/cards
0 [H58006000encode]: HDMI_58006000_e - HDMI 58006000.encoder
HDMI 58006000.encoder
root@devuan:/sys/devices/platform/usb-phy@1#
[ 10.819122] ALSA device list:
[ 10.832641] #0: HDMI 58006000.encoder
[ 10.842407] Waiting 10 sec before mounting root device...

I think I should have the required options enabled...

CONFIG_SND_OMAP_SOC=y
CONFIG_SND_OMAP_SOC_DMIC=y
CONFIG_SND_OMAP_SOC_MCBSP=y
CONFIG_SND_OMAP_SOC_MCPDM=y
CONFIG_SND_OMAP_SOC_HDMI_AUDIO=y
# CONFIG_SND_OMAP_SOC_RX51 is not set
# CONFIG_SND_OMAP_SOC_N9 is not set
CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y
CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y
# CONFIG_SND_SOC_IMG is not set

#
# STMicroelectronics STM32 SOC audio support
#
# CONFIG_SND_SOC_XTFPGA_I2S is not set
# CONFIG_ZX_TDM is not set
CONFIG_SND_SOC_I2C_AND_SPI=y
CONFIG_SND_SOC_CPCAP=y

Any ideas?

Thanks,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.49 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-22 23:50:53

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi Pavel,

On Thu, Mar 22, 2018 at 09:48:05PM +0100, Pavel Machek wrote:
> Hi!
>
> > Add sound support to Motorola Droid 4 using simple-soundcard
> > and CPCAP's audio codec. This does not yet correctly represent
> > the whole audio routing, since McBSP3 is also connected to
> > Bluetooth and MDM6600 modem (and probably also 4G modem).
> > These extra DAI links are not yet supported and have not been
> > tested.
>
> I applied the series on top v4.16-rc5, but I can't seem to get it
> to work:
>
> root@devuan:/sys/devices/platform/usb-phy@1# cat /proc/asound/cards
> 0 [H58006000encode]: HDMI_58006000_e - HDMI 58006000.encoder
> HDMI 58006000.encoder
> root@devuan:/sys/devices/platform/usb-phy@1#
> [ 10.819122] ALSA device list:
> [ 10.832641] #0: HDMI 58006000.encoder
> [ 10.842407] Waiting 10 sec before mounting root device...
>
> I think I should have the required options enabled...
>
> CONFIG_SND_OMAP_SOC=y
> CONFIG_SND_OMAP_SOC_DMIC=y
> CONFIG_SND_OMAP_SOC_MCBSP=y
> CONFIG_SND_OMAP_SOC_MCPDM=y
> CONFIG_SND_OMAP_SOC_HDMI_AUDIO=y

That's the SoC (OMAP) side.

> # CONFIG_SND_OMAP_SOC_RX51 is not set
> # CONFIG_SND_OMAP_SOC_N9 is not set
> CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y
> CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y

That's not needed (but does not hurt). The Droid 4
has no TWL companion chip and uses CPCAP instead.

> # CONFIG_SND_SOC_IMG is not set
>
> #
> # STMicroelectronics STM32 SOC audio support
> #
> # CONFIG_SND_SOC_XTFPGA_I2S is not set
> # CONFIG_ZX_TDM is not set
> CONFIG_SND_SOC_I2C_AND_SPI=y
> CONFIG_SND_SOC_CPCAP=y

That's the codec side.

> Any ideas?

You probably did not enable the soundcard driver, that binds against
"audio-graph-card" compatible and connects the codec driver with the
SoC driver: CONFIG_SND_AUDIO_GRAPH_CARD

-- Sebastian


Attachments:
(No filename) (1.84 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-23 10:32:44

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi,

On Fri, Mar 23, 2018 at 11:09:30AM +0100, Pavel Machek wrote:
> Hi!
>
> > > # CONFIG_SND_OMAP_SOC_RX51 is not set
> > > # CONFIG_SND_OMAP_SOC_N9 is not set
> > > CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y
> > > CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y
> >
> > That's not needed (but does not hurt). The Droid 4
> > has no TWL companion chip and uses CPCAP instead.
>
> Aha, thanks. I was doing wild experiments to get something that
> boots... I turned them off.
>
> > > Any ideas?
> >
> > You probably did not enable the soundcard driver, that binds against
> > "audio-graph-card" compatible and connects the codec driver with the
> > SoC driver: CONFIG_SND_AUDIO_GRAPH_CARD
>
> Ok, that certainly changed things; I am now getting this:
>
> Mar 23 08:39:17 devuan kernel: [ 11.633605] asoc-audio-graph-card soundcard: GPIO lookup for
> consumer pa
> Mar 23 08:39:17 devuan kernel: [ 11.644958] asoc-audio-graph-card soundcard: using device tr
> ee for GPIO lookup
> Mar 23 08:39:17 devuan kernel: [ 11.656677] of_get_named_gpiod_flags: can't parse 'pa-gpios'
> property of node '/soundcard[0]'
> Mar 23 08:39:17 devuan kernel: [ 11.669738] of_get_named_gpiod_flags: can't parse 'pa-gpio'
> property of node '/soundcard[0]'
> Mar 23 08:39:17 devuan kernel: [ 11.682617] asoc-audio-graph-card soundcard: using lookup ta
> bles for GPIO lookup
> Mar 23 08:39:17 devuan kernel: [ 11.694427] asoc-audio-graph-card soundcard: lookup for GPIO
> pa failed

That's not an error, but just some debug messages. Consider
disabling CONFIG_DEBUG_GPIO to get rid of them.

> Indeed the dts does not seem to contain any gpios

It's optional and does not exist on Droid 4.

> soundcard {
> compatible = "audio-graph-card";
> label = "Droid 4 Audio";
>
> simple-graph-card,widgets =
> "Speaker", "Earpiece",
> "Speaker", "Loudspeaker",
> "Headphone", "Headphone Jack",
> "Microphone", "Internal Mic";
>
> simple-graph-card,routing =
> "Earpiece", "EP",
> "Loudspeaker", "SPKR",
> "Headphone Jack", "HSL",
> "Headphone Jack", "HSR",
> "MICR", "Internal Mic";
>
> dais = <&mcbsp2_port>, <&mcbsp3_port>;
> };
>
> Any more ideas? :-)

Make sure, that the device was not proped properly (cat
/proc/asound/cards) and post the real error? :)

-- Sebastian


Attachments:
(No filename) (2.53 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-23 11:07:48

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> > > > Any ideas?
> > >
> > > You probably did not enable the soundcard driver, that binds against
> > > "audio-graph-card" compatible and connects the codec driver with the
> > > SoC driver: CONFIG_SND_AUDIO_GRAPH_CARD
> >
> > Ok, that certainly changed things; I am now getting this:
> >
> > Mar 23 08:39:17 devuan kernel: [ 11.633605] asoc-audio-graph-card soundcard: GPIO lookup for
> > consumer pa
> > Mar 23 08:39:17 devuan kernel: [ 11.644958] asoc-audio-graph-card soundcard: using device tr
> > ee for GPIO lookup
> > Mar 23 08:39:17 devuan kernel: [ 11.656677] of_get_named_gpiod_flags: can't parse 'pa-gpios'
> > property of node '/soundcard[0]'
> > Mar 23 08:39:17 devuan kernel: [ 11.669738] of_get_named_gpiod_flags: can't parse 'pa-gpio'
> > property of node '/soundcard[0]'
> > Mar 23 08:39:17 devuan kernel: [ 11.682617] asoc-audio-graph-card soundcard: using lookup ta
> > bles for GPIO lookup
> > Mar 23 08:39:17 devuan kernel: [ 11.694427] asoc-audio-graph-card soundcard: lookup for GPIO
> > pa failed
>
> That's not an error, but just some debug messages. Consider
> disabling CONFIG_DEBUG_GPIO to get rid of them.
>
> > Indeed the dts does not seem to contain any gpios
>
> It's optional and does not exist on Droid 4.
>
> > soundcard {
> > compatible = "audio-graph-card";
> > label = "Droid 4 Audio";
> >
> > simple-graph-card,widgets =
> > "Speaker", "Earpiece",
> > "Speaker", "Loudspeaker",
> > "Headphone", "Headphone Jack",
> > "Microphone", "Internal Mic";
> >
> > simple-graph-card,routing =
> > "Earpiece", "EP",
> > "Loudspeaker", "SPKR",
> > "Headphone Jack", "HSL",
> > "Headphone Jack", "HSR",
> > "MICR", "Internal Mic";
> >
> > dais = <&mcbsp2_port>, <&mcbsp3_port>;
> > };
> >
> > Any more ideas? :-)
>
> Make sure, that the device was not proped properly (cat
> /proc/asound/cards) and post the real error? :)

Unfortunately, that are last messages from asoc-audio-graph-card

Mar 23 08:39:17 devuan kernel: [ 11.694427] asoc-audio-graph-card
soundcard: lookup for GPIO pa failed

and no, it is not detected:

root@devuan:/home/user# cat /proc/asound/cards
0 [H58006000encode]: HDMI_58006000_e - HDMI 58006000.encoder
HDMI 58006000.encoder
root@devuan:/home/user#

Hmm. Is it possible that EPROBEDEFFER is playing with me again?

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (2.75 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-23 11:10:46

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> Make sure, that the device was not proped properly (cat
> /proc/asound/cards) and post the real error? :)

Standby... looks like I cleaned up too much of "unused" config.



--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (329.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-23 11:17:31

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> > # CONFIG_SND_OMAP_SOC_RX51 is not set
> > # CONFIG_SND_OMAP_SOC_N9 is not set
> > CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y
> > CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y
>
> That's not needed (but does not hurt). The Droid 4
> has no TWL companion chip and uses CPCAP instead.

Aha, thanks. I was doing wild experiments to get something that
boots... I turned them off.

> > Any ideas?
>
> You probably did not enable the soundcard driver, that binds against
> "audio-graph-card" compatible and connects the codec driver with the
> SoC driver: CONFIG_SND_AUDIO_GRAPH_CARD

Ok, that certainly changed things; I am now getting this:

Mar 23 08:39:17 devuan kernel: [ 11.633605] asoc-audio-graph-card soundcard: GPIO lookup for
consumer pa
Mar 23 08:39:17 devuan kernel: [ 11.644958] asoc-audio-graph-card soundcard: using device tr
ee for GPIO lookup
Mar 23 08:39:17 devuan kernel: [ 11.656677] of_get_named_gpiod_flags: can't parse 'pa-gpios'
property of node '/soundcard[0]'
Mar 23 08:39:17 devuan kernel: [ 11.669738] of_get_named_gpiod_flags: can't parse 'pa-gpio'
property of node '/soundcard[0]'
Mar 23 08:39:17 devuan kernel: [ 11.682617] asoc-audio-graph-card soundcard: using lookup ta
bles for GPIO lookup
Mar 23 08:39:17 devuan kernel: [ 11.694427] asoc-audio-graph-card soundcard: lookup for GPIO
pa failed

Indeed the dts does not seem to contain any gpios

soundcard {
compatible = "audio-graph-card";
label = "Droid 4 Audio";

simple-graph-card,widgets =
"Speaker", "Earpiece",
"Speaker", "Loudspeaker",
"Headphone", "Headphone Jack",
"Microphone", "Internal Mic";

simple-graph-card,routing =
"Earpiece", "EP",
"Loudspeaker", "SPKR",
"Headphone Jack", "HSL",
"Headphone Jack", "HSR",
"MICR", "Internal Mic";

dais = <&mcbsp2_port>, <&mcbsp3_port>;
};

Any more ideas? :-)

Thanks,

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (2.24 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-23 14:12:34

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> > Any more ideas? :-)
>
> Make sure, that the device was not proped properly (cat
> /proc/asound/cards) and post the real error? :)

Oh and, audio now works for me, so

Tested-by: Pavel Machek <[email protected]>

for the series.

Thanks,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (411.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-23 14:12:53

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> That's not an error, but just some debug messages. Consider
> disabling CONFIG_DEBUG_GPIO to get rid of them.
>
> > Indeed the dts does not seem to contain any gpios
>
> It's optional and does not exist on Droid 4.
>
> > soundcard {
...
> > };
> >
> > Any more ideas? :-)
>
> Make sure, that the device was not proped properly (cat
> /proc/asound/cards) and post the real error? :)

Thanks, it is indeed a config problem. When I disabled "unrelated"
options, these got disabled, too:

They can be only selected, and there's nothing to select them in Droid
4 case.
Pavel

diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 2772414..7860b6e 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -4,13 +4,13 @@ config SND_OMAP_SOC
select SND_DMAENGINE_PCM

config SND_OMAP_SOC_DMIC
- tristate
+ tristate "dmic"

config SND_OMAP_SOC_MCBSP
- tristate
+ tristate "mcbsp"

config SND_OMAP_SOC_MCPDM
- tristate
+ tristate "mcpdm"

config SND_OMAP_SOC_HDMI_AUDIO
tristate "HDMI audio support for OMAP4+ based SoCs"






--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.24 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-26 14:20:04

by Pavel Machek

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

Hi!

Do you have any ideas what needs to be done for voice calls support? I
can talk to the modem and start a call.

Then something like this (untested!) is certainly needed. Probably
more...

Thanks,
Pavel

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index aedb267..7646f68 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -1280,6 +1280,60 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
return 0;
}

+static int cpcap_incall_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct device *dev = codec->dev;
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ static const u16 reg_cdi = CPCAP_REG_CDI;
+ int rate = params_rate(params);
+ int channels = params_channels(params);
+ int direction = substream->stream;
+ u16 val, mask;
+ int err;
+
+ dev_dbg(dev, "Incall setup HW params: rate=%d, direction=%d, chan=%d",
+ rate, direction, channels);
+
+ /* codec, 1 in original code is CPCAP_REG_CC
+ codec, 2 is CPCAP_REG_CDI
+ codec, 5 is CPCAP_REG_TXI */
+
+ if (/* cpcap->codec_strm_cnt == */ 1) {
+ /*
+ if (pdata->voice_type != VOICE_TYPE_QC)
+ printk("FIXME: Only MDM6600 support is implemented here.\n");
+ */
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, 0xffff, 0xAE02);
+ if (err) printk("cpcap error %d\n", __LINE__);
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, 0xffff, 0x6120);
+ if (err) printk("cpcap error %d\n", __LINE__);
+
+ err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
+ printk("Configured stream\n");
+ }
+
+ /* (direction == SNDRV_PCM_STREAM_CAPTURE) ?? */
+ if (substream->stream) { /* up link */
+ unsigned int set = CPCAP_BIT_AUDIHPF_1 | CPCAP_BIT_AUDIHPF_0;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, set, set);
+ if (err) printk("cpcap error %d\n", __LINE__);
+
+ set = CPCAP_BIT_MB_ON1L | CPCAP_BIT_MB_ON1R;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, set, set);
+ } else { /* down link */
+ unsigned int set = CPCAP_BIT_AUDOHPF_1 | CPCAP_BIT_AUDOHPF_0;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, set, set);
+ if (err) printk("cpcap error %d\n", __LINE__);
+ }
+
+ return err;
+}
+
static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
unsigned int freq, int dir)
{
@@ -1394,6 +1448,14 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
.digital_mute = cpcap_voice_set_mute,
};

+static const struct snd_soc_dai_ops cpcap_dai_incall_ops = {
+ /* FIXME */
+ .hw_params = cpcap_incall_hw_params,
+ .set_sysclk = cpcap_voice_set_dai_sysclk,
+ .set_fmt = cpcap_voice_set_dai_fmt,
+ .digital_mute = cpcap_voice_set_mute,
+};
+
static struct snd_soc_dai_driver cpcap_dai[] = {
{
.id = 0,
@@ -1426,6 +1488,26 @@ static struct snd_soc_dai_driver cpcap_dai[] = {
},
.ops = &cpcap_dai_voice_ops,
},
+{
+ .id = 2,
+ .name = "cpcap in-call",
+ .playback = {
+ .stream_name = "InCall DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &cpcap_dai_incall_ops,
+},
+/* FIXME: this misses bt-call, cpcap bt, BPvoice, FM */
};

static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)






--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (3.78 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-26 16:00:07

by Sebastian Reichel

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

Hi,

On Mon, Mar 26, 2018 at 04:16:38PM +0200, Pavel Machek wrote:
> Do you have any ideas what needs to be done for voice calls
> support?

Sure.

> I can talk to the modem and start a call.

Doing an AT query is the easy part :)

> Then something like this (untested!) is certainly needed.
> Probably more...

I intentionally left this part out. The CPCAP codec has two DAIs
and not 3+. The code you just added is a hack from Motorola. Their
driver is full of hacks and it's obvious its author(s) did not
fully understand the ASoC APIs.

My understanding is, that we only need to replace the audio-graph-card
driver to something more complex. The VOICE DAI needs to be configured
differently based on the use case:

call:
* mode=i2s
* freq=26000000
* samprate=16000 or samprate=8000

bt voice:
* mode="4 timeslots network"
* freq=26000000
* samprate=8000
* CPCAP_BIT_MIC2_TIMESLOT1

bt call:
* mode="4 timeslots network"
* freq=19200000
* samprate=8000
* CPCAP_BIT_MIC2_TIMESLOT1

"audio-graph-card" is not capable of doing this. I was planning to
try "audio-graph-scu-card" in combination with adding codecs for the
modem and BT to DT. If that does not work we need a Droid 4 specific
soundcard driver.

Either way "audio-graph-card" is not the correct driver for D4. I
added it nevertheless, since it gets audio working for now and there
is no risk of DT breakage. Old *.dtb will continue to work with the
"audio-graph-card" even after we switch to something else.

-- Sebastian

> Thanks,
> Pavel
>
> diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
> index aedb267..7646f68 100644
> --- a/sound/soc/codecs/cpcap.c
> +++ b/sound/soc/codecs/cpcap.c
> @@ -1280,6 +1280,60 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
> return 0;
> }
>
> +static int cpcap_incall_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_codec *codec = dai->codec;
> + struct device *dev = codec->dev;
> + struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
> + static const u16 reg_cdi = CPCAP_REG_CDI;
> + int rate = params_rate(params);
> + int channels = params_channels(params);
> + int direction = substream->stream;
> + u16 val, mask;
> + int err;
> +
> + dev_dbg(dev, "Incall setup HW params: rate=%d, direction=%d, chan=%d",
> + rate, direction, channels);
> +
> + /* codec, 1 in original code is CPCAP_REG_CC
> + codec, 2 is CPCAP_REG_CDI
> + codec, 5 is CPCAP_REG_TXI */
> +
> + if (/* cpcap->codec_strm_cnt == */ 1) {
> + /*
> + if (pdata->voice_type != VOICE_TYPE_QC)
> + printk("FIXME: Only MDM6600 support is implemented here.\n");
> + */
> +
> + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, 0xffff, 0xAE02);
> + if (err) printk("cpcap error %d\n", __LINE__);
> +
> + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, 0xffff, 0x6120);
> + if (err) printk("cpcap error %d\n", __LINE__);
> +
> + err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
> + printk("Configured stream\n");
> + }
> +
> + /* (direction == SNDRV_PCM_STREAM_CAPTURE) ?? */
> + if (substream->stream) { /* up link */
> + unsigned int set = CPCAP_BIT_AUDIHPF_1 | CPCAP_BIT_AUDIHPF_0;
> + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, set, set);
> + if (err) printk("cpcap error %d\n", __LINE__);
> +
> + set = CPCAP_BIT_MB_ON1L | CPCAP_BIT_MB_ON1R;
> + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, set, set);
> + } else { /* down link */
> + unsigned int set = CPCAP_BIT_AUDOHPF_1 | CPCAP_BIT_AUDOHPF_0;
> + err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, set, set);
> + if (err) printk("cpcap error %d\n", __LINE__);
> + }
> +
> + return err;
> +}
> +
> static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
> unsigned int freq, int dir)
> {
> @@ -1394,6 +1448,14 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
> .digital_mute = cpcap_voice_set_mute,
> };
>
> +static const struct snd_soc_dai_ops cpcap_dai_incall_ops = {
> + /* FIXME */
> + .hw_params = cpcap_incall_hw_params,
> + .set_sysclk = cpcap_voice_set_dai_sysclk,
> + .set_fmt = cpcap_voice_set_dai_fmt,
> + .digital_mute = cpcap_voice_set_mute,
> +};
> +
> static struct snd_soc_dai_driver cpcap_dai[] = {
> {
> .id = 0,
> @@ -1426,6 +1488,26 @@ static struct snd_soc_dai_driver cpcap_dai[] = {
> },
> .ops = &cpcap_dai_voice_ops,
> },
> +{
> + .id = 2,
> + .name = "cpcap in-call",
> + .playback = {
> + .stream_name = "InCall DL",
> + .channels_min = 1,
> + .channels_max = 2,
> + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
> + .formats = SNDRV_PCM_FMTBIT_S16_LE,
> + },
> + .capture = {
> + .stream_name = "Capture",
> + .channels_min = 1,
> + .channels_max = 2,
> + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
> + .formats = SNDRV_PCM_FMTBIT_S16_LE,
> + },
> + .ops = &cpcap_dai_incall_ops,
> +},
> +/* FIXME: this misses bt-call, cpcap bt, BPvoice, FM */
> };
>
> static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
>
>
>
>
>
>
> --
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html



Attachments:
(No filename) (5.33 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-26 20:33:01

by Pavel Machek

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

Hi!

> On Mon, Mar 26, 2018 at 04:16:38PM +0200, Pavel Machek wrote:
> > Do you have any ideas what needs to be done for voice calls
> > support?
>
> Sure.

:-).

> > I can talk to the modem and start a call.
>
> Doing an AT query is the easy part :)

Well, yes. Doing it right (ofono, etc) is not that easy.

> > Then something like this (untested!) is certainly needed.
> > Probably more...
>
> I intentionally left this part out. The CPCAP codec has two DAIs
> and not 3+. The code you just added is a hack from Motorola. Their
> driver is full of hacks and it's obvious its author(s) did not
> fully understand the ASoC APIs.

Ok.

> My understanding is, that we only need to replace the audio-graph-card
> driver to something more complex. The VOICE DAI needs to be configured
> differently based on the use case:
>
> call:
> * mode=i2s
> * freq=26000000
> * samprate=16000 or samprate=8000

Ok, lets ignore bluetooth for now. There is "normal" mode, and then
there's "call" mode, right? Where's "normal" mode configured?

Could we simply always configure the VOICE DAI in the call mode? Yes,
it would limit samplerates to 8 or 16k, but .. that's not too
important limitation for voice codec...?

> "audio-graph-card" is not capable of doing this. I was planning to
> try "audio-graph-scu-card" in combination with adding codecs for the
> modem and BT to DT. If that does not work we need a Droid 4 specific
> soundcard driver.
>
> Either way "audio-graph-card" is not the correct driver for D4. I
> added it nevertheless, since it gets audio working for now and there
> is no risk of DT breakage. Old *.dtb will continue to work with the
> "audio-graph-card" even after we switch to something else.

Well, you'll still cause regressions when you change the dts, as
people will have wrong .config for new dts.

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (2.00 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-26 23:11:39

by Sebastian Reichel

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

Hi,

On Mon, Mar 26, 2018 at 10:31:54PM +0200, Pavel Machek wrote:
> Hi!
>
> > On Mon, Mar 26, 2018 at 04:16:38PM +0200, Pavel Machek wrote:
> > > Do you have any ideas what needs to be done for voice calls
> > > support?
> >
> > Sure.
>
> :-).
>
> > > I can talk to the modem and start a call.
> >
> > Doing an AT query is the easy part :)
>
> Well, yes. Doing it right (ofono, etc) is not that easy.

I agree. That can be worked on independently.

> > > Then something like this (untested!) is certainly needed.
> > > Probably more...
> >
> > I intentionally left this part out. The CPCAP codec has two DAIs
> > and not 3+. The code you just added is a hack from Motorola. Their
> > driver is full of hacks and it's obvious its author(s) did not
> > fully understand the ASoC APIs.
>
> Ok.
>
> > My understanding is, that we only need to replace the audio-graph-card
> > driver to something more complex. The VOICE DAI needs to be configured
> > differently based on the use case:
> >
> > call:
> > * mode=i2s
> > * freq=26000000
> > * samprate=16000 or samprate=8000
>
> Ok, lets ignore bluetooth for now. There is "normal" mode, and then
> there's "call" mode, right? Where's "normal" mode configured?

mcbsp3_port: port {
cpu_dai3: endpoint {
dai-format = "dsp_a";
frame-master = <&cpcap_audio_codec1>;
bitclock-master = <&cpcap_audio_codec1>;
remote-endpoint = <&cpcap_audio_codec1>;
};
};

> Could we simply always configure the VOICE DAI in the call mode? Yes,
> it would limit samplerates to 8 or 16k, but .. that's not too
> important limitation for voice codec...?

I think we could configure "normal" mode to use the same settings
as call mode. But ASoC will disable CPCAP, since there will be no
active user without ASoC knowing about the modem.

> > "audio-graph-card" is not capable of doing this. I was planning to
> > try "audio-graph-scu-card" in combination with adding codecs for the
> > modem and BT to DT. If that does not work we need a Droid 4 specific
> > soundcard driver.
> >
> > Either way "audio-graph-card" is not the correct driver for D4. I
> > added it nevertheless, since it gets audio working for now and there
> > is no risk of DT breakage. Old *.dtb will continue to work with the
> > "audio-graph-card" even after we switch to something else.
>
> Well, you'll still cause regressions when you change the dts, as
> people will have wrong .config for new dts.

That's correct, the .config needs to change. I think that's
ok, because the only alternative is having no audio support
at all until the soundcard driver is ready. This means, that
you also need to change .config once its ready (in case you
want to use it).

-- Sebastian


Attachments:
(No filename) (2.71 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-27 12:18:21

by Mark Brown

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

On Mon, Mar 26, 2018 at 05:58:28PM +0200, Sebastian Reichel wrote:

> My understanding is, that we only need to replace the audio-graph-card
> driver to something more complex. The VOICE DAI needs to be configured
> differently based on the use case:

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.

> "audio-graph-card" is not capable of doing this. I was planning to
> try "audio-graph-scu-card" in combination with adding codecs for the
> modem and BT to DT. If that does not work we need a Droid 4 specific
> soundcard driver.

That's just the audio graph card with some hacks for working with a DPCM
based SoC driver set.


Attachments:
(No filename) (724.00 B)
signature.asc (499.00 B)
Download all attachments

2018-03-27 20:42:50

by Pavel Machek

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

Hi!

> > > My understanding is, that we only need to replace the audio-graph-card
> > > driver to something more complex. The VOICE DAI needs to be configured
> > > differently based on the use case:
> > >
> > > call:
> > > * mode=i2s
> > > * freq=26000000
> > > * samprate=16000 or samprate=8000
> >
> > Ok, lets ignore bluetooth for now. There is "normal" mode, and then
> > there's "call" mode, right? Where's "normal" mode configured?
>
> mcbsp3_port: port {
> cpu_dai3: endpoint {
> dai-format = "dsp_a";
> frame-master = <&cpcap_audio_codec1>;
> bitclock-master = <&cpcap_audio_codec1>;
> remote-endpoint = <&cpcap_audio_codec1>;
> };
> };

Hmm. Can't tell mode and freq here easily. Does it default to i2s /
26000000?

> > Could we simply always configure the VOICE DAI in the call mode? Yes,
> > it would limit samplerates to 8 or 16k, but .. that's not too
> > important limitation for voice codec...?
>
> I think we could configure "normal" mode to use the same settings
> as call mode. But ASoC will disable CPCAP, since there will be no
> active user without ASoC knowing about the modem.

Ok, but then we can just start playback/recording with the call, and
everything should work, no?

But Motorola code seems to do different magic according to modem type,
so things may not be as easy.

if (pdata->voice_type == VOICE_TYPE_STE) {
/* STE_M570 */
ret = cpcap_audio_reg_write(codec, 2, 0xAE06);
if (rate == 16000)
ret |= cpcap_audio_reg_write(codec, 1, 0x8720);
else
ret |= cpcap_audio_reg_write(codec, 1, 0x8120);
} else if (pdata->voice_type == VOICE_TYPE_QC) {
/* MDM6600 */
ret = cpcap_audio_reg_write(codec, 2, 0xAE02);
if (rate == 16000) {
ret |= cpcap_audio_reg_write(codec, 1, 0x6720);
} else {
ret |= cpcap_audio_reg_write(codec, 1, 0x6120);
}


> > > "audio-graph-card" is not capable of doing this. I was planning to
> > > try "audio-graph-scu-card" in combination with adding codecs for the
> > > modem and BT to DT. If that does not work we need a Droid 4 specific
> > > soundcard driver.
> > >
> > > Either way "audio-graph-card" is not the correct driver for D4. I
> > > added it nevertheless, since it gets audio working for now and there
> > > is no risk of DT breakage. Old *.dtb will continue to work with the
> > > "audio-graph-card" even after we switch to something else.
> >
> > Well, you'll still cause regressions when you change the dts, as
> > people will have wrong .config for new dts.
>
> That's correct, the .config needs to change. I think that's
> ok, because the only alternative is having no audio support
> at all until the soundcard driver is ready. This means, that
> you also need to change .config once its ready (in case you
> want to use it).

Ok, another problem seems to be that spaces in audio device name seem
to confuse the userland.

Aha, here:

user@devuan:~$ cat /proc/asound/cards
0 [H58006000encode]: HDMI_58006000_e - HDMI 58006000.encoder
HDMI 58006000.encoder
1 [Audio ]: Droid_4_Audio - Droid 4 Audio
Droid 4 Audio

See how the card is refered simply as "Audio"? Same thing then happens
in alsa "state" file:

state.Audio {
control.1 {

.

Best regards,

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (3.73 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-27 20:52:57

by Tony Lindgren

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

* Pavel Machek <[email protected]> [180327 20:42]:
> But Motorola code seems to do different magic according to modem type,
> so things may not be as easy.
>
> if (pdata->voice_type == VOICE_TYPE_STE) {
> /* STE_M570 */
> ret = cpcap_audio_reg_write(codec, 2, 0xAE06);
> if (rate == 16000)
> ret |= cpcap_audio_reg_write(codec, 1, 0x8720);
> else
> ret |= cpcap_audio_reg_write(codec, 1, 0x8120);
> } else if (pdata->voice_type == VOICE_TYPE_QC) {
> /* MDM6600 */
> ret = cpcap_audio_reg_write(codec, 2, 0xAE02);
> if (rate == 16000) {
> ret |= cpcap_audio_reg_write(codec, 1, 0x6720);
> } else {
> ret |= cpcap_audio_reg_write(codec, 1, 0x6120);
> }

The parts not related to mdm6600 can be ignored until somebody
gets some device other modems working with mainline kernel.

And if there are any refrerences to W3GLTE, or wrigley, it
supposedly never worked for voice calls and only data.

Regards,

Tony

2018-03-27 22:24:03

by Sebastian Reichel

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

Hi Mark,

On Tue, Mar 27, 2018 at 08:14:41PM +0800, Mark Brown wrote:
> On Mon, Mar 26, 2018 at 05:58:28PM +0200, Sebastian Reichel wrote:
>
> > My understanding is, that we only need to replace the audio-graph-card
> > driver to something more complex. The VOICE DAI needs to be configured
> > differently based on the use case:
>
> 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.

Oh nice. So the Droid 4 hardware wiring looks like this (at least
according to my understanding):

+----------+ +-------------+
| 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.

> > "audio-graph-card" is not capable of doing this. I was planning to
> > try "audio-graph-scu-card" in combination with adding codecs for the
> > modem and BT to DT. If that does not work we need a Droid 4 specific
> > soundcard driver.
>
> That's just the audio graph card with some hacks for working with a DPCM
> based SoC driver set.

Ok.

-- Sebastian


Attachments:
(No filename) (1.79 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-28 02:30:42

by Mark Brown

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

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? 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.


Attachments:
(No filename) (1.36 kB)
signature.asc (499.00 B)
Download all attachments

2018-03-28 09:05:29

by Pavel Machek

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

Hi!

> > I can talk to the modem and start a call.
>
> Doing an AT query is the easy part :)
>
> > Then something like this (untested!) is certainly needed.
> > Probably more...
>
> I intentionally left this part out. The CPCAP codec has two DAIs
> and not 3+. The code you just added is a hack from Motorola. Their
> driver is full of hacks and it's obvious its author(s) did not
> fully understand the ASoC APIs.
>
> My understanding is, that we only need to replace the audio-graph-card
> driver to something more complex. The VOICE DAI needs to be configured
> differently based on the use case:

Does the voice part work for you? I configured all the mixers to
voice, and then am using

sudo aplay -D plughw:CARD=Audio,DEV=1 /usr/share/sounds/alsa/Front_Center.wav -r 16000
X11 connection rejected because of wrong authentication.
xcb_connection_has_error() returned true
Playing WAVE '/usr/share/sounds/alsa/Front_Center.wav' : Signed 16 bit
Little Endian, Rate 48000 Hz, Mono
user@devuan:/my/tui/rweb$

to play the test sound. But I get white noise, not a test sound
:-(. [This also shows problem with card naming.]

Any ideas?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.30 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-28 09:39:02

by Pavel Machek

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

Hi!

> > > I can talk to the modem and start a call.
> >
> > Doing an AT query is the easy part :)
> >
> > > Then something like this (untested!) is certainly needed.
> > > Probably more...
> >
> > I intentionally left this part out. The CPCAP codec has two DAIs
> > and not 3+. The code you just added is a hack from Motorola. Their
> > driver is full of hacks and it's obvious its author(s) did not
> > fully understand the ASoC APIs.
> >
> > My understanding is, that we only need to replace the audio-graph-card
> > driver to something more complex. The VOICE DAI needs to be configured
> > differently based on the use case:
>
> Does the voice part work for you? I configured all the mixers to
> voice, and then am using

I tried with 8kHz, 8-bit, too:

user@devuan:/my/tui/rweb$ arecord -D plughw:CARD=Audio,DEV=1 -t wav
--max-file-time 30 mon.wav
Recording WAVE 'mon.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
^CAborted by signal Interrupt...
arecord: pcm_read:2103: read error: Interrupted system call
user@devuan:/my/tui/rweb$ aplay -D plughw:CARD=Audio,DEV=1 -t wav
mon.wav
Playing WAVE 'mon.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
^CAborted by signal Interrupt...

Recording works okay, but playback produces ugly noise (not white this
time). If I copy mon.wav to PC, it playes back in pretty acceptable
quality.

So summary

HIFI DAI works
VOICE DAI recording is ok
VOICE DAI playbacks plays noise.

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.59 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-28 14:05:12

by Sebastian Reichel

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

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.

> 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?

-- Sebastian


Attachments:
(No filename) (2.04 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-29 01:46:28

by Tony Lindgren

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

Hi,

* Sebastian Reichel <[email protected]> [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 <[email protected]>
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(-)

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

2018-03-29 13:37:41

by Sebastian Reichel

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

Hi,

On Wed, Mar 28, 2018 at 06:45:07PM -0700, Tony Lindgren wrote:
> Hi,
>
> * Sebastian Reichel <[email protected]> [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 <[email protected]>
> 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


Attachments:
(No filename) (9.65 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-29 14:00:49

by Tony Lindgren

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

* Sebastian Reichel <[email protected]> [180329 13:37]:
> Hi,
>
> On Wed, Mar 28, 2018 at 06:45:07PM -0700, Tony Lindgren wrote:
> > Hi,
> >
> > * Sebastian Reichel <[email protected]> [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

2018-03-29 14:11:28

by Pavel Machek

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

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
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (612.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-29 14:23:54

by Tony Lindgren

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

* Pavel Machek <[email protected]> [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

2018-03-29 15:47:34

by Sebastian Reichel

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

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


Attachments:
(No filename) (1.36 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-29 16:08:22

by Tony Lindgren

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

* Sebastian Reichel <[email protected]> [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



2018-03-29 16:10:51

by Pavel Machek

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

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
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.73 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-29 16:37:44

by Tony Lindgren

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

* Pavel Machek <[email protected]> [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

2018-03-29 16:38:47

by Pavel Machek

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

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
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (736.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-29 16:42:58

by Tony Lindgren

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

* Pavel Machek <[email protected]> [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


2018-03-29 18:24:19

by Pavel Machek

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

On Thu 2018-03-29 09:34:50, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [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
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (2.93 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-29 18:41:39

by Pavel Machek

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

On Thu 2018-03-29 09:41:13, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [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.

Thanks. I got call working including outgoing audio: in capture
settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
the other phone muted, so I don't yet know if such call would be of
usable quality.

Thanks!
Pavel

--- tony.as 2018-03-29 18:29:41.715742372 +0000
+++ mic.as 2018-03-29 18:33:40.910759649 +0000
@@ -258,8 +258,8 @@
0404: 0000
0408: 0000
040c: 0000
-0410: 0014
-0414: 0104
+0410: 0004
+0414: 0105
0418: 000e
041c: 00ff
0420: 44d3
@@ -515,8 +515,8 @@
0808: ae0a
080c: 0078
0810: 003c
-0814: 0cc0
-0818: 0610
+0814: 0cc4
+0818: 061f
081c: 0006
0820: 0b2c
0824: 0606
@@ -641,13 +641,13 @@
0a00: 0000
0a04: 23b6
0a08: 002b
-0a0c: 1530
+0a0c: 18ec
0a10: 0000
-0a14: 4e54
-0a18: 0036
+0a14: 6a90
+0a18: 0040
0a1c: 0000
0a20: 0000
-0a24: 0738
+0a24: 0b40
0a28: 0000
0a2c: 0000
0a30: 0000
@@ -769,12 +769,12 @@
0c00: 9004
0c04: 0136
0c08: 0000
-0c0c: 02fb
+0c0c: 02fc
0c10: 01da
-0c14: 015b
-0c18: 0300
-0c1c: 0271
-0c20: 01e5
+0c14: 015a
+0c18: 02fe
+0c1c: 0270
+0c20: 01f5
0c24: 0000
0c28: 0204
0c2c: 0205


Attachments:
(No filename) (1.96 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-29 21:57:42

by Tony Lindgren

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

* Pavel Machek <[email protected]> [180329 18:41]:
> Thanks. I got call working including outgoing audio: in capture
> settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
> the other phone muted, so I don't yet know if such call would be of
> usable quality.

Great, good to hear that :)

Tony



> --- tony.as 2018-03-29 18:29:41.715742372 +0000
> +++ mic.as 2018-03-29 18:33:40.910759649 +0000
> @@ -258,8 +258,8 @@
> 0404: 0000
> 0408: 0000
> 040c: 0000
> -0410: 0014
> -0414: 0104
> +0410: 0004
> +0414: 0105
> 0418: 000e
> 041c: 00ff
> 0420: 44d3
> @@ -515,8 +515,8 @@
> 0808: ae0a
> 080c: 0078
> 0810: 003c
> -0814: 0cc0
> -0818: 0610
> +0814: 0cc4
> +0818: 061f
> 081c: 0006
> 0820: 0b2c
> 0824: 0606
> @@ -641,13 +641,13 @@
> 0a00: 0000
> 0a04: 23b6
> 0a08: 002b
> -0a0c: 1530
> +0a0c: 18ec
> 0a10: 0000
> -0a14: 4e54
> -0a18: 0036
> +0a14: 6a90
> +0a18: 0040
> 0a1c: 0000
> 0a20: 0000
> -0a24: 0738
> +0a24: 0b40
> 0a28: 0000
> 0a2c: 0000
> 0a30: 0000
> @@ -769,12 +769,12 @@
> 0c00: 9004
> 0c04: 0136
> 0c08: 0000
> -0c0c: 02fb
> +0c0c: 02fc
> 0c10: 01da
> -0c14: 015b
> -0c18: 0300
> -0c1c: 0271
> -0c20: 01e5
> +0c14: 015a
> +0c18: 02fe
> +0c1c: 0270
> +0c20: 01f5
> 0c24: 0000
> 0c28: 0204
> 0c2c: 0205



2018-03-29 22:00:21

by Tony Lindgren

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

* Pavel Machek <[email protected]> [180329 18:07]:
> On Thu 2018-03-29 09:34:50, Tony Lindgren wrote:
> > * Pavel Machek <[email protected]> [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



2018-03-30 10:39:40

by Pavel Machek

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

On Thu 2018-03-29 14:56:13, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [180329 18:41]:
> > Thanks. I got call working including outgoing audio: in capture
> > settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
> > the other phone muted, so I don't yet know if such call would be of
> > usable quality.
>
> Great, good to hear that :)

I also got ofonod to work, with rather crazy hacks. But I now have
incoming/outgoing calls with GUI :-).

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (635.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-30 10:59:10

by Sebastian Reichel

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

Hi,

On Thu, Mar 29, 2018 at 09:06:11AM -0700, Tony Lindgren wrote:
> * Sebastian Reichel <[email protected]> [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


Attachments:
(No filename) (1.23 kB)
signature.asc (849.00 B)
Download all attachments

2018-03-30 13:09:12

by Merlijn Wajer

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

On 30/03/18 12:37, Pavel Machek wrote:
> On Thu 2018-03-29 14:56:13, Tony Lindgren wrote:
>> * Pavel Machek <[email protected]> [180329 18:41]:
>>> Thanks. I got call working including outgoing audio: in capture
>>> settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
>>> the other phone muted, so I don't yet know if such call would be of
>>> usable quality.
>>
>> Great, good to hear that :)
>
> I also got ofonod to work, with rather crazy hacks. But I now have
> incoming/outgoing calls with GUI :-).

Would you mind sharing those hacks - I would like to play around with
ofonod as well. Maybe I can help with a way forward.

Cheers,
Merlijn


Attachments:
signature.asc (235.00 B)
OpenPGP digital signature

2018-03-30 15:24:00

by Tony Lindgren

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

* Merlijn Wajer <[email protected]> [180330 13:09]:
> On 30/03/18 12:37, Pavel Machek wrote:
> > On Thu 2018-03-29 14:56:13, Tony Lindgren wrote:
> >> * Pavel Machek <[email protected]> [180329 18:41]:
> >>> Thanks. I got call working including outgoing audio: in capture
> >>> settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
> >>> the other phone muted, so I don't yet know if such call would be of
> >>> usable quality.
> >>
> >> Great, good to hear that :)
> >
> > I also got ofonod to work, with rather crazy hacks. But I now have
> > incoming/outgoing calls with GUI :-).
>
> Would you mind sharing those hacks - I would like to play around with
> ofonod as well. Maybe I can help with a way forward.

Yeah that would be fun to play with :)

Below is a patch that works better at least for ModemManager,
does anybody have ideas what the unused three ports might be?

I wonder if ofono can use /dev/ttyUSB0 CQDM port?

Regards,

Tony

8< -------------------------
From tony Mon Sep 17 00:00:00 2001
From: Tony Lindgren <[email protected]>
Date: Sun, 19 Nov 2017 19:55:56 -0800
Subject: [PATCH] USB: qcaux: Add droid 4 mdm6600 modem

We have five USB ports on mdm6600 modem and does not have the same
layout as layout as Gobi 1K/2K/etc devices listed in qcserial.c

So we should not be adding them to qcserial.c but instead use
qcaux.c or option.c as noted by Dan Williams <[email protected]>.

The ttyUSB ports detected by ModemManager are:

ttyUSB0 CQDM-capable
ttyUSB1 no response
ttyUSB2 no response
ttyUSB3 no response
ttyUSB4 AT-capable

Note that it takes a while for ModemManager to start while it's
detecting the ports, so we may want to eventually limit the ports.

So far no luck finding out what the unused three ports are, maybe
there is NMEA there if somebody knows how to enable it.

Signed-off-by: Tony Lingren <[email protected]>
---
drivers/usb/serial/qcaux.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -66,6 +66,7 @@ static const struct usb_device_id id_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */
{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1fac, 0x0151, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2a70, 0xff, 0xff, 0xff) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
--
2.16.3

2018-03-30 15:38:55

by Pavel Machek

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

Hi!

> > >> Great, good to hear that :)
> > >
> > > I also got ofonod to work, with rather crazy hacks. But I now have
> > > incoming/outgoing calls with GUI :-).
> >
> > Would you mind sharing those hacks - I would like to play around with
> > ofonod as well. Maybe I can help with a way forward.
>
> Yeah that would be fun to play with :)

Ok, I thought I should clean them up first, but hey...

sudo emacs /etc/udev/rules.d/55-modem.rules
KERNEL=="ttyUSB4", ENV{OFONO_DRIVER}="g1"

sudo udevadm trigger

And now, the crazy hack follows. Note I'm using AT interface -- which
is probably not good idea.

Anyway, network/signal strength is detected, and calls seem to work.

diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 68b89862..3a9f4bc0 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -440,6 +440,8 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
if (data->vendor != OFONO_VENDOR_SIMCOM)
at_ack_delivery(sms);

+ return;
+
err:
ofono_error("Unable to parse CMT notification");
}
diff --git a/plugins/g1.c b/plugins/g1.c
index d915a565..dd4e735d 100644
--- a/plugins/g1.c
+++ b/plugins/g1.c
@@ -60,7 +60,8 @@ static void g1_debug(const char *str, void *user_data)
/* Detect hardware, and initialize if found */
static int g1_probe(struct ofono_modem *modem)
{
- DBG("");
+ DBG("probing G1");
+ DBG("probing G1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

return 0;
}
@@ -97,14 +98,21 @@ static int g1_enable(struct ofono_modem *modem)

DBG("");

+ DBG("enabling G1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
device = ofono_modem_get_string(modem, "Device");
- if (device == NULL)
- return -EINVAL;
+ // if (device == NULL)
+ // return -EINVAL;
+ device = "/dev/ttyUSB4";
+
+ DBG("");

channel = g_at_tty_open(device, NULL);
if (channel == NULL)
return -EIO;

+ DBG("");
+
syntax = g_at_syntax_new_gsm_permissive();
chat = g_at_chat_new(channel, syntax);
g_io_channel_unref(channel);
@@ -116,11 +124,14 @@ static int g1_enable(struct ofono_modem *modem)
if (getenv("OFONO_AT_DEBUG"))
g_at_chat_set_debug(chat, g1_debug, "");

+ DBG("");
ofono_modem_set_data(modem, chat);

+ DBG("");
/* ensure modem is in a known state; verbose on, echo/quiet off */
g_at_chat_send(chat, "ATE0Q0V1", NULL, NULL, NULL, NULL);

+ DBG("");
/* power up modem */
g_at_chat_send(chat, "AT+CFUN=1", NULL, cfun_set_on_cb, modem, NULL);

@@ -191,18 +202,56 @@ static void g1_post_sim(struct ofono_modem *modem)
ofono_message_waiting_register(mw);
}

+static void g1_post_online(struct ofono_modem *modem)
+{
+ DBG();
+}
+
+static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ GAtChat *chat = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_at_chat_unref(chat);
+ ofono_modem_set_data(modem, NULL);
+
+ // if (ok)
+ // ofono_modem_set_online(modem, TRUE);
+}
+
+static void g1_set_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t cb, void *user_data)
+{
+ GAtChat *chat = ofono_modem_get_data(modem);
+ char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4";
+
+ DBG("modem %p %s", modem, online ? "online" : "offline");
+
+ if (g_at_chat_send(chat, command, NULL,
+ set_online_cb, modem, NULL) > 0)
+ return;
+
+ //CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+}
+
static struct ofono_modem_driver g1_driver = {
.name = "g1",
.probe = g1_probe,
.remove = g1_remove,
.enable = g1_enable,
.disable = g1_disable,
+ // .set_online = g1_set_online,
.pre_sim = g1_pre_sim,
.post_sim = g1_post_sim,
+ .post_online = g1_post_online,
};

static int g1_init(void)
{
+ DBG("g1_init!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
return ofono_modem_driver_register(&g1_driver);
}

diff --git a/plugins/udevng.c b/plugins/udevng.c
index ff5d41af..3e0cdf81 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1250,6 +1250,7 @@ static struct {
{ "cinterion", setup_serial_modem },
{ "nokiacdma", setup_serial_modem },
{ "sim900", setup_serial_modem },
+ { "g1", setup_serial_modem },
{ "wavecom", setup_wavecom },
{ "tc65", setup_tc65 },
{ "ehs6", setup_ehs6 },
@@ -1407,7 +1408,7 @@ static void add_serial_device(struct udev_device *dev)

mdev = get_serial_modem_device(dev);
if (!mdev) {
- DBG("Device is missing required OFONO_DRIVER property");
+ //DBG("Device %s %s is missing required OFONO_DRIVER property", udev_device_get_devpath(mdev), udev_device_get_syspath(mdev));
return;
}

@@ -1419,6 +1420,9 @@ static void add_serial_device(struct udev_device *dev)

devnode = udev_device_get_devnode(dev);

+ DBG("Got OFONO_DRIVER!!!! driver %s path %s\n", driver, devpath);
+
+
if (!syspath || !devpath)
return;

@@ -1578,8 +1582,6 @@ static struct {
{ "mbm", "cdc_ether", "0930" },
{ "mbm", "cdc_ncm", "0930" },
{ "hso", "hso" },
- { "gobi", "qmi_wwan" },
- { "gobi", "qcserial" },
{ "sierra", "qmi_wwan", "1199" },
{ "sierra", "qcserial", "1199" },
{ "sierra", "sierra" },
@@ -1602,6 +1604,8 @@ static struct {
{ "telit", "cdc_acm", "1bc7", "0021" },
{ "telitqmi", "qmi_wwan", "1bc7", "1201" },
{ "telitqmi", "option", "1bc7", "1201" },
+ { "telitqmi", "qmi_wwan", "22b8", "2a70" },
+ { "telitqmi", "option", "22b8", "2a70" },
{ "nokia", "option", "0421", "060e" },
{ "nokia", "option", "0421", "0623" },
{ "samsung", "option", "04e8", "6889" },
@@ -1717,10 +1721,12 @@ static void check_device(struct udev_device *device)
return;
}

+#if 0
if ((g_str_equal(bus, "usb") == TRUE) ||
(g_str_equal(bus, "usbmisc") == TRUE))
check_usb_device(device);
else
+#endif
add_serial_device(device);

}
@@ -1746,17 +1752,20 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
return TRUE;

for (i = 0; driver_list[i].name; i++) {
+ DBG("comparing %s %s", driver_list[i].name, modem->driver);
if (g_str_equal(driver_list[i].name, modem->driver) == FALSE)
continue;

- if (driver_list[i].setup(modem) == TRUE) {
+ /* if (driver_list[i].setup(modem) == TRUE) */ {
ofono_modem_set_string(modem->modem, "SystemPath",
syspath);
ofono_modem_register(modem->modem);
+ DBG("create modem is okay?");
return FALSE;
}
}

+ DBG("create modem is maybe not okay?");
return TRUE;
}

@@ -1796,6 +1805,7 @@ static void enumerate_devices(struct udev *context)
udev_enumerate_unref(enumerate);

g_hash_table_foreach_remove(modem_list, create_modem, NULL);
+ DBG("Enumerate devices ok?");
}

static struct udev *udev_ctx;
@@ -1811,6 +1821,8 @@ static gboolean check_modem_list(gpointer user_data)

g_hash_table_foreach_remove(modem_list, create_modem, NULL);

+ DBG("Check modem list ok?");
+
return FALSE;
}

@@ -1820,6 +1832,8 @@ static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
struct udev_device *device;
const char *action;

+ DBG("udev event");
+
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
ofono_warn("Error with udev monitor channel");
udev_watch = 0;
@@ -1838,11 +1852,14 @@ static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
if (udev_delay > 0)
g_source_remove(udev_delay);

+ DBG("udev event add -> check");
check_device(device);

udev_delay = g_timeout_add_seconds(1, check_modem_list, NULL);
- } else if (g_str_equal(action, "remove") == TRUE)
+ } else if (g_str_equal(action, "remove") == TRUE) {
+ DBG("udev event remove -> remove");
remove_device(device);
+ }

udev_device_unref(device);

@@ -1892,8 +1909,10 @@ static int detect_init(void)
return -EIO;
}

+ ofono_warn("detect_init...");
modem_list = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, destroy_modem);
+ ofono_warn("detect_init 2...");

udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "tty", NULL);
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "usb", NULL);
diff --git a/src/modem.c b/src/modem.c
index 0cee861f..d8dde772 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -603,12 +603,14 @@ static gboolean modem_has_sim(struct ofono_modem *modem)

static gboolean modem_is_always_online(struct ofono_modem *modem)
{
+ DBG();
if (modem->driver->set_online == NULL)
return TRUE;

if (ofono_modem_get_boolean(modem, "AlwaysOnline") == TRUE)
return TRUE;

+ DBG("not always");
return FALSE;
}

@@ -720,8 +722,10 @@ static void sim_state_watch(enum ofono_sim_state new_state, void *user)
modem_change_state(modem, MODEM_STATE_OFFLINE);

/* Modem is always online, proceed to online state. */
- if (modem_is_always_online(modem) == TRUE)
+ if (modem_is_always_online(modem) == TRUE) {
set_online(modem, TRUE);
+ modem->online = TRUE;
+ }

if (modem->online == TRUE)
modem_change_state(modem, MODEM_STATE_ONLINE);
@@ -1882,13 +1886,17 @@ struct ofono_modem *ofono_modem_create(const char *name, const char *type)
else
snprintf(path, sizeof(path), "/%s", name);

- if (!dbus_validate_path(path, NULL))
+ if (!dbus_validate_path(path, NULL)) {
+ DBG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!bad dbus path");
return NULL;
+ }

modem = g_try_new0(struct ofono_modem, 1);

- if (modem == NULL)
+ if (modem == NULL) {
+ DBG("!!!out of memory?!");
return modem;
+ }

modem->path = g_strdup(path);
modem->driver_type = g_strdup(type);
@@ -1900,6 +1908,7 @@ struct ofono_modem *ofono_modem_create(const char *name, const char *type)
if (name == NULL)
next_modem_id += 1;

+ DBG("Created new modem, path %s", path);
return modem;
}

diff --git a/src/network.c b/src/network.c
index ae3175d4..700183c0 100644
--- a/src/network.c
+++ b/src/network.c
@@ -980,6 +980,7 @@ static DBusMessage *network_scan(DBusConnection *conn,
{
struct ofono_netreg *netreg = data;

+ DBG();
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);

@@ -991,6 +992,7 @@ static DBusMessage *network_scan(DBusConnection *conn,

netreg->pending = dbus_message_ref(msg);

+ DBG();
netreg->driver->list_operators(netreg, operator_list_callback, netreg);

return NULL;
diff --git a/src/voicecall.c b/src/voicecall.c
index e4f6a4c0..2c637e58 100644
--- a/src/voicecall.c
+++ b/src/voicecall.c
@@ -1492,6 +1492,7 @@ static int voicecall_dial(struct ofono_voicecall *vc, const char *number,
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
struct ofono_phone_number ph;

+ DBG("");
if (g_slist_length(vc->call_list) >= MAX_VOICE_CALLS)
return -EPERM;






--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (10.88 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-30 17:52:20

by Pavel Machek

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

On Fri 2018-03-30 15:07:24, Merlijn Wajer wrote:
> On 30/03/18 12:37, Pavel Machek wrote:
> > On Thu 2018-03-29 14:56:13, Tony Lindgren wrote:
> >> * Pavel Machek <[email protected]> [180329 18:41]:
> >>> Thanks. I got call working including outgoing audio: in capture
> >>> settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
> >>> the other phone muted, so I don't yet know if such call would be of
> >>> usable quality.
> >>
> >> Great, good to hear that :)
> >
> > I also got ofonod to work, with rather crazy hacks. But I now have
> > incoming/outgoing calls with GUI :-).
>
> Would you mind sharing those hacks - I would like to play around with
> ofonod as well. Maybe I can help with a way forward.

Okay. Here's less hacky version of the hack, but still using AT
commands. You still need to set up udev, as described in the other
mail.

And... it seems I can have a qmi connection, too, but that's topic for
other email.

Good luck,
Pavel


diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index 68b89862..3a9f4bc0 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -440,6 +440,8 @@ static void at_cmt_notify(GAtResult *result, gpointer user_data)
if (data->vendor != OFONO_VENDOR_SIMCOM)
at_ack_delivery(sms);

+ return;
+
err:
ofono_error("Unable to parse CMT notification");
}
diff --git a/plugins/udevng.c b/plugins/udevng.c
index ff5d41af..a4b18488 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -233,10 +233,11 @@ static gboolean setup_gobi(struct modem_info *modem)
}
}

+ DBG("qmi=%s net=%s mdm=%s gps=%s diag=%s", qmi, net, mdm, gps, diag);
+
if (qmi == NULL || mdm == NULL || net == NULL)
return FALSE;

- DBG("qmi=%s net=%s mdm=%s gps=%s diag=%s", qmi, net, mdm, gps, diag);

ofono_modem_set_string(modem->modem, "Device", qmi);
ofono_modem_set_string(modem->modem, "Modem", mdm);
@@ -1250,6 +1251,7 @@ static struct {
{ "cinterion", setup_serial_modem },
{ "nokiacdma", setup_serial_modem },
{ "sim900", setup_serial_modem },
+ { "g1", setup_serial_modem },
{ "wavecom", setup_wavecom },
{ "tc65", setup_tc65 },
{ "ehs6", setup_ehs6 },
@@ -1578,8 +1580,6 @@ static struct {
{ "mbm", "cdc_ether", "0930" },
{ "mbm", "cdc_ncm", "0930" },
{ "hso", "hso" },
- { "gobi", "qmi_wwan" },
- { "gobi", "qcserial" },
{ "sierra", "qmi_wwan", "1199" },
{ "sierra", "qcserial", "1199" },
{ "sierra", "sierra" },
@@ -1602,6 +1602,8 @@ static struct {
{ "telit", "cdc_acm", "1bc7", "0021" },
{ "telitqmi", "qmi_wwan", "1bc7", "1201" },
{ "telitqmi", "option", "1bc7", "1201" },
+ { "telitqmi", "qmi_wwan", "22b8", "2a70" },
+ { "telitqmi", "option", "22b8", "2a70" },
{ "nokia", "option", "0421", "060e" },
{ "nokia", "option", "0421", "0623" },
{ "samsung", "option", "04e8", "6889" },
@@ -1717,10 +1719,12 @@ static void check_device(struct udev_device *device)
return;
}

+#if 0
if ((g_str_equal(bus, "usb") == TRUE) ||
(g_str_equal(bus, "usbmisc") == TRUE))
check_usb_device(device);
else
+#endif
add_serial_device(device);

}
@@ -1749,14 +1753,17 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
if (g_str_equal(driver_list[i].name, modem->driver) == FALSE)
continue;

+ DBG("Attempting modem setup, driver %s", modem->driver);
if (driver_list[i].setup(modem) == TRUE) {
ofono_modem_set_string(modem->modem, "SystemPath",
syspath);
ofono_modem_register(modem->modem);
return FALSE;
}
+ DBG("Modem setup failed, driver %s", modem->driver);
}

+ DBG("Modem setup failed or not in driver_list?");
return TRUE;
}




--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (3.83 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-30 18:06:56

by Pavel Machek

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

On Fri 2018-03-30 19:50:50, Pavel Machek wrote:
> On Fri 2018-03-30 15:07:24, Merlijn Wajer wrote:
> > On 30/03/18 12:37, Pavel Machek wrote:
> > > On Thu 2018-03-29 14:56:13, Tony Lindgren wrote:
> > >> * Pavel Machek <[email protected]> [180329 18:41]:
> > >>> Thanks. I got call working including outgoing audio: in capture
> > >>> settings, right->mic 1, Mic1 + Mic2 in alsamixer -> 100%. But I had
> > >>> the other phone muted, so I don't yet know if such call would be of
> > >>> usable quality.
> > >>
> > >> Great, good to hear that :)
> > >
> > > I also got ofonod to work, with rather crazy hacks. But I now have
> > > incoming/outgoing calls with GUI :-).
> >
> > Would you mind sharing those hacks - I would like to play around with
> > ofonod as well. Maybe I can help with a way forward.
>
> Okay. Here's less hacky version of the hack, but still using AT
> commands. You still need to set up udev, as described in the other
> mail.
>
> And... it seems I can have a qmi connection, too, but that's topic for
> other email.

This, applied on top of previous patch, gives me some kind of qmi
connection, AFAICT. I can enable/online a modem, but nothing else
works.

LocationReporting is advertised but does not work. dial-number does
not work either. But from list-modems, it looks like some kind of
communication works...
Pavel

user@devuan:/my/ofono/test$ sudo python2 ./list-modems
[ /gobi_0 ]
SystemPath = /sys/devices/platform/44000000.ocp/4a064000.usbhshost/4a064800.ohci/usb2/2-1
Features = sim gps
Emergency = 0
Powered = 1
Lockdown = 0
Interfaces = org.ofono.SimManager org.ofono.LocationReporting org.ofono.VoiceCallManager
Online = 1
Model = 196
Revision = M6600A-SCAUHSZ-3.1.3310T 1 [Jun 09 2011 17:00:00]
Type = hardware
Serial = 809DE736
Manufacturer = QUALCOMM INCORPORATED
[ org.ofono.SimManager ]
Present = 0
[ org.ofono.LocationReporting ]
Type = nmea
Enabled = 0
[ org.ofono.VoiceCallManager ]
EmergencyNumbers = 08 000 999 110 112 911 118 119

user@devuan:/my/ofono/test$




diff --git a/doc/location-reporting-api.txt b/doc/location-reporting-api.txt
index 21e346d4..ff0a35dc 100644
--- a/doc/location-reporting-api.txt
+++ b/doc/location-reporting-api.txt
@@ -13,7 +13,7 @@ Methods dict GetProperties()
filedescriptor Request()

Asks to turn ON the NMEA stream and supplies the
- gps device file descriptor. The external cliend should
+ gps device file descriptor. The external client should
use the file descriptor to receive the NMEA data.

Possible Errors: [service].Error.InProgress
diff --git a/plugins/udevng.c b/plugins/udevng.c
index a4b18488..1c6a6679 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -234,9 +234,10 @@ static gboolean setup_gobi(struct modem_info *modem)
}

DBG("qmi=%s net=%s mdm=%s gps=%s diag=%s", qmi, net, mdm, gps, diag);
-
+#if 0
if (qmi == NULL || mdm == NULL || net == NULL)
return FALSE;
+#endif


ofono_modem_set_string(modem->modem, "Device", qmi);
@@ -1251,7 +1252,7 @@ static struct {
{ "cinterion", setup_serial_modem },
{ "nokiacdma", setup_serial_modem },
{ "sim900", setup_serial_modem },
- { "g1", setup_serial_modem },
+ // { "g1", setup_serial_modem },
{ "wavecom", setup_wavecom },
{ "tc65", setup_tc65 },
{ "ehs6", setup_ehs6 },
@@ -1602,8 +1603,8 @@ static struct {
{ "telit", "cdc_acm", "1bc7", "0021" },
{ "telitqmi", "qmi_wwan", "1bc7", "1201" },
{ "telitqmi", "option", "1bc7", "1201" },
- { "telitqmi", "qmi_wwan", "22b8", "2a70" },
- { "telitqmi", "option", "22b8", "2a70" },
+ { "gobi", "qmi_wwan", "22b8", "2a70" },
+ { "gobi", "option", "22b8", "2a70" },
{ "nokia", "option", "0421", "060e" },
{ "nokia", "option", "0421", "0623" },
{ "samsung", "option", "04e8", "6889" },
@@ -1719,7 +1720,7 @@ static void check_device(struct udev_device *device)
return;
}

-#if 0
+#if 1
if ((g_str_equal(bus, "usb") == TRUE) ||
(g_str_equal(bus, "usbmisc") == TRUE))
check_usb_device(device);


Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (4.25 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-30 20:48:21

by Pavel Machek

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

Hi!

> > > Would you mind sharing those hacks - I would like to play around with
> > > ofonod as well. Maybe I can help with a way forward.
> >
> > Okay. Here's less hacky version of the hack, but still using AT
> > commands. You still need to set up udev, as described in the other
> > mail.
> >
> > And... it seems I can have a qmi connection, too, but that's topic for
> > other email.
>
> This, applied on top of previous patch, gives me some kind of qmi
> connection, AFAICT. I can enable/online a modem, but nothing else
> works.
>
> LocationReporting is advertised but does not work. dial-number does
> not work either. But from list-modems, it looks like some kind of
> communication works...

Ok, strange.

So there's ofonod in the maemo-leste already.

user@devuan:~$ /usr/sbin/ofonod -v
1.22

...and it seems to somehow work with the droid 4, in default
configuration, thinking it is "Gobi" modem.

user@devuan:/my/ofono$ sudo python2 test/list-modems
[ /gobi_0 ]
Features = sms net rat ussd sim gps
Emergency = 0
Powered = 1
Lockdown = 0
Interfaces = org.ofono.SmartMessaging
org.ofono.PushNotification
org.ofono.MessageManager
org.ofono.NetworkRegistration
org.ofono.RadioSettings
org.ofono.SupplementaryServices
org.ofono.NetworkMonitor org.ofono.MessageWaiting
org.ofono.AllowedAccessPoints org.ofono.SimManager
org.ofono.LocationReporting
org.ofono.VoiceCallManager
Online = 1
Model = 196
Revision = M6600A-SCAUHSZ-3.1.3310T 1
[Jun 09 2011 17:00:00]
Type = hardware
...

... and it seems to kind-of work. Even incoming SMSes work, which I
could not get to work in AT mode. Otoh, voice calls do not, so...

Confused,
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.93 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-30 22:33:24

by Pavel Machek

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

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

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (0.98 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-31 14:57:52

by Pavel Machek

[permalink] [raw]
Subject: call/normal switch was Re: omap4-droid4: voice call support was

Hi!

> 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?

This is not proper patch yet, but it should be a step in that
direction...

If someone knows how to express cleanly "active support for modem is
the same as active audio playback", let me know....

Best regards,
Pavel

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 3b53bd0..7aaa4db 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -221,18 +221,18 @@ struct cpcap_reg_info {
};

static const struct cpcap_reg_info cpcap_default_regs[] = {
- { CPCAP_REG_CC, 0xFFFF, 0x0000 },
- { CPCAP_REG_CC, 0xFFFF, 0x0000 },
- { CPCAP_REG_CDI, 0xBFFF, 0x0000 },
+ { CPCAP_REG_CC, 0xFFFF, 0x60cf },
+ { CPCAP_REG_CDI, 0xBFFF, 0xae0a },
{ CPCAP_REG_SDAC, 0x0FFF, 0x0000 },
{ CPCAP_REG_SDACDI, 0x3FFF, 0x0000 },
- { CPCAP_REG_TXI, 0x0FDF, 0x0000 },
- { CPCAP_REG_TXMP, 0x0FFF, 0x0400 },
- { CPCAP_REG_RXOA, 0x01FF, 0x0000 },
- { CPCAP_REG_RXVC, 0xFF3C, 0x0000 },
- { CPCAP_REG_RXCOA, 0x07FF, 0x0000 },
- { CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 },
+ { CPCAP_REG_TXI, 0x0FFF, 0x0CC0 },
+ { CPCAP_REG_TXMP, 0x0FFF, 0x0610 },
+ { CPCAP_REG_RXOA, 0x01FF, 0x0006 },
+ { CPCAP_REG_RXVC, 0xFF3C, 0x0B2C },
+ { CPCAP_REG_RXCOA, 0x07FF, 0x0606 },
+ { CPCAP_REG_RXSDOA, 0x1FFF, 0x0600 },
{ CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 },
+ { CPCAP_REG_VAUDIOC, 0xFFFF, 0x0025 },
{ CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN),
BIT(CPCAP_BIT_A2_FREE_RUN) },
};
@@ -330,6 +330,11 @@ static const char * const cpcap_in_left_mux_texts[] = {
"Off", "Mic 2", "Ext Left"
};

+static const char * const cpcap_mode_texts[] = {
+ "Normal", "Call"
+};
+
+
/*
* input muxes use unusual register layout, so that we need to use custom
* getter/setter methods
@@ -354,6 +359,8 @@ static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);

+static SOC_ENUM_SINGLE_DECL(cpcap_mode_enum, 0, 9, cpcap_mode_texts);
+
static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -442,6 +449,86 @@ static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
return 0;
}

+static int mode;
+
+static int cpcap_mode_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int err;
+
+ ucontrol->value.enumerated.item[0] = mode;
+
+ return 0;
+}
+
+static int cpcap_mode_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ unsigned int mask = BIT(e->shift_l);
+ int err;
+
+ printk("Requested mode %d\n", muxval);
+
+ mode = muxval;
+
+ switch (muxval) {
+ case 1:
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
+ 0xffff, 0x0025); // OK
+ if (err)
+ goto out;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
+ 0xffff, 0x60cf); // OK
+ if (err)
+ goto out;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+ 0xffff, 0xae0a); // OK
+ if (err)
+ goto out;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ 0xffff, 0x0cc0);
+ if (err)
+ goto out;
+
+ mask = 1 << CPCAP_BIT_PGA_CDC_EN | 0x200;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+ mask, mask);
+ if (err)
+ printk("error #3\n");
+
+ mask = 1 << CPCAP_BIT_A2_LDSP_L_EN | 1 << CPCAP_BIT_A2_LDSP_R_EN;
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
+ mask, mask);
+ if (err)
+ printk("error #2\n");
+
+ err = regmap_update_bits(cpcap->regmap, 0x814,
+ 0x0400, 0x0400);
+ if (err)
+ printk("error #1\n");
+
+ default:
+ break;
+ }
+
+ // FIXME
+// snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+ return 0;
+out: printk("Something failed\n");
+ return -EINVAL;
+}
+
static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -630,6 +717,11 @@ static const struct snd_kcontrol_new cpcap_earpiece_mux =
SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum,
cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);

+static const struct snd_kcontrol_new cpcap_mode =
+ SOC_DAPM_ENUM_EXT("Mode", cpcap_mode_enum,
+ cpcap_mode_get_enum, cpcap_mode_put_enum);
+
+
static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = {
SOC_DAPM_SINGLE("HiFi Mono Playback Switch",
CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0),
@@ -771,6 +863,10 @@ static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = {
SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0,
&cpcap_emu_left_mux),

+
+ SND_SOC_DAPM_MUX("Mode", SND_SOC_NOPM, 0, 0,
+ &cpcap_mode),
+
/* Output Amplifier */
SND_SOC_DAPM_PGA("Earpiece PGA",
CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0),
@@ -816,6 +912,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Microphone 1 PGA", NULL, "VAUDIO"},
{"Microphone 2 PGA", NULL, "VAUDIO"},

+ /* FIXME */
+ {"Mode", NULL, "Voice TX"},
+
/* Stream -> AIF */
{"HiFi RX", NULL, "HiFi Playback"},
{"Voice RX", NULL, "Voice Playback"},



--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (6.14 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-31 18:21:05

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Pavel Machek <[email protected]> [180331 14:56]:
> Hi!
>
> > 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?
>
> This is not proper patch yet, but it should be a step in that
> direction...

Cool :) Microphone still does not work for me.. I tried tweaking
the alsamixer settings but no mic. This is with cold boot with
droid4-kexecboot if that might make a difference, we may have
some register uninitialized somewhere. Any ideas?

FYI, I got one of the remaining n_gsm issues tracked down yesterday,
at least one more bug to go. Things only work with n_gsm debug
enabled right now for some reason..

Regards,

Tony

2018-03-31 19:24:08

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [180331 14:56]:
> > Hi!
> >
> > > 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?
> >
> > This is not proper patch yet, but it should be a step in that
> > direction...
>
> Cool :) Microphone still does not work for me.. I tried tweaking
> the alsamixer settings but no mic. This is with cold boot with
> droid4-kexecboot if that might make a difference, we may have
> some register uninitialized somewhere. Any ideas?

Ok, I was focusing on the speaker side.

alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
should work, according to my notes, but not recently tested and not
tested against real human.

I'll attempt to test it, but something in my userland shuts down
system just after boot 60% of time, which is rather annoying.

> FYI, I got one of the remaining n_gsm issues tracked down yesterday,
> at least one more bug to go. Things only work with n_gsm debug
> enabled right now for some reason..

I don't know why I need n_gsm, but I have my fingers crossed. :-).

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.49 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-31 19:49:49

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Pavel Machek <[email protected]> [180331 19:21]:
> On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > * Pavel Machek <[email protected]> [180331 14:56]:
> > > Hi!
> > >
> > > > 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?
> > >
> > > This is not proper patch yet, but it should be a step in that
> > > direction...
> >
> > Cool :) Microphone still does not work for me.. I tried tweaking
> > the alsamixer settings but no mic. This is with cold boot with
> > droid4-kexecboot if that might make a difference, we may have
> > some register uninitialized somewhere. Any ideas?
>
> Ok, I was focusing on the speaker side.
>
> alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> should work, according to my notes, but not recently tested and not
> tested against real human.

In alsamixer after setting the second "Speaker" to "Voice" and "Mode"
to "Call" and "Left" to "Mic 2" and "Right" to "Mic 1" and doing a
test call the mic does not work, speaker works though.

After the call in alsamixer, setting the second "Speaker" to "HiFi",
and "Mode" to "Normal" mode, I can record a wav file and play it back
just fine. But this only works for me after reloading snd-soc-cpcap.ko
after the voice call.

> I'll attempt to test it, but something in my userland shuts down
> system just after boot 60% of time, which is rather annoying.

Hmm battery voltage too low? We have cpcap_battery_irq_thread()
call orderly_poweroff() on lowbpl interrupt.

> > FYI, I got one of the remaining n_gsm issues tracked down yesterday,
> > at least one more bug to go. Things only work with n_gsm debug
> > enabled right now for some reason..
>
> I don't know why I need n_gsm, but I have my fingers crossed. :-).

More features it seems :) But sounds like you're all set for now
with USB access.

Regards,

Tony




2018-03-31 19:49:49

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > * Pavel Machek <[email protected]> [180331 14:56]:
> > > Hi!
> > >
> > > > 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?
> > >
> > > This is not proper patch yet, but it should be a step in that
> > > direction...
> >
> > Cool :) Microphone still does not work for me.. I tried tweaking
> > the alsamixer settings but no mic. This is with cold boot with
> > droid4-kexecboot if that might make a difference, we may have
> > some register uninitialized somewhere. Any ideas?
>
> Ok, I was focusing on the speaker side.
>
> alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> should work, according to my notes, but not recently tested and not
> tested against real human.
>
> I'll attempt to test it, but something in my userland shuts down
> system just after boot 60% of time, which is rather annoying.

Hmm. So I tried again, and setting Mic1 and back in the capture
settings crashed the modem. Bang, disconnected from the USB.

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.47 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-31 19:56:51

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > * Pavel Machek <[email protected]> [180331 14:56]:
> > > > Hi!
> > > >
> > > > > 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?
> > > >
> > > > This is not proper patch yet, but it should be a step in that
> > > > direction...
> > >
> > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > the alsamixer settings but no mic. This is with cold boot with
> > > droid4-kexecboot if that might make a difference, we may have
> > > some register uninitialized somewhere. Any ideas?
> >
> > Ok, I was focusing on the speaker side.
> >
> > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > should work, according to my notes, but not recently tested and not
> > tested against real human.
> >
> > I'll attempt to test it, but something in my userland shuts down
> > system just after boot 60% of time, which is rather annoying.
>
> Hmm. So I tried again, and setting Mic1 and back in the capture
> settings crashed the modem. Bang, disconnected from the USB.

Next try, and it worked this time.

_Before the call_, set mode to Normal and then Call. Then go to
capture, and set 100 100 Mic2 Mic1. Then place a call,

AT+CFUN=1
OK
ATD6;

If you change Mic1 setting, GSM modem will likely crash.

Good luck,
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.83 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-03-31 23:45:35

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Pavel Machek <[email protected]> [180331 19:56]:
> On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > > the alsamixer settings but no mic. This is with cold boot with
> > > > droid4-kexecboot if that might make a difference, we may have
> > > > some register uninitialized somewhere. Any ideas?
> > >
> > > Ok, I was focusing on the speaker side.
> > >
> > > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > > should work, according to my notes, but not recently tested and not
> > > tested against real human.
> > >
> > > I'll attempt to test it, but something in my userland shuts down
> > > system just after boot 60% of time, which is rather annoying.
> >
> > Hmm. So I tried again, and setting Mic1 and back in the capture
> > settings crashed the modem. Bang, disconnected from the USB.
>
> Next try, and it worked this time.
>
> _Before the call_, set mode to Normal and then Call. Then go to
> capture, and set 100 100 Mic2 Mic1. Then place a call,
>
> AT+CFUN=1
> OK
> ATD6;

No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
works, but ATD command on it just hangs the USB interface
and I have to reload phy-mapphone-mdm6600 to reset the
modem.

> If you change Mic1 setting, GSM modem will likely crash.

Have not seen that one here :)

Regards,

Tony

2018-04-01 06:50:31

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sat 2018-03-31 16:43:14, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [180331 19:56]:
> > On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > > > the alsamixer settings but no mic. This is with cold boot with
> > > > > droid4-kexecboot if that might make a difference, we may have
> > > > > some register uninitialized somewhere. Any ideas?
> > > >
> > > > Ok, I was focusing on the speaker side.
> > > >
> > > > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > > > should work, according to my notes, but not recently tested and not
> > > > tested against real human.
> > > >
> > > > I'll attempt to test it, but something in my userland shuts down
> > > > system just after boot 60% of time, which is rather annoying.
> > >
> > > Hmm. So I tried again, and setting Mic1 and back in the capture
> > > settings crashed the modem. Bang, disconnected from the USB.
> >
> > Next try, and it worked this time.
> >
> > _Before the call_, set mode to Normal and then Call. Then go to
> > capture, and set 100 100 Mic2 Mic1. Then place a call,
> >
> > AT+CFUN=1
> > OK
> > ATD6;
>
> No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
> works, but ATD command on it just hangs the USB interface
> and I have to reload phy-mapphone-mdm6600 to reset the
> modem.

I realized where the difference is.

I have ofonod running there, one from maemo leste distribution. It
manages to talk to the modem somehow. I guess that accounts for the
difference.

I guess I should get it out of the picture....
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.88 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-01 13:23:06

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sat 2018-03-31 16:43:14, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [180331 19:56]:
> > On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > > > the alsamixer settings but no mic. This is with cold boot with
> > > > > droid4-kexecboot if that might make a difference, we may have
> > > > > some register uninitialized somewhere. Any ideas?
> > > >
> > > > Ok, I was focusing on the speaker side.
> > > >
> > > > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > > > should work, according to my notes, but not recently tested and not
> > > > tested against real human.
> > > >
> > > > I'll attempt to test it, but something in my userland shuts down
> > > > system just after boot 60% of time, which is rather annoying.
> > >
> > > Hmm. So I tried again, and setting Mic1 and back in the capture
> > > settings crashed the modem. Bang, disconnected from the USB.
> >
> > Next try, and it worked this time.
> >
> > _Before the call_, set mode to Normal and then Call. Then go to
> > capture, and set 100 100 Mic2 Mic1. Then place a call,
> >
> > AT+CFUN=1
> > OK
> > ATD6;
>
> No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
> works, but ATD command on it just hangs the USB interface
> and I have to reload phy-mapphone-mdm6600 to reset the
> modem.

Test call with real human worked (thanks to Rolf K.), I could hear him
well but he reported call was very quiet. And that was with capture
settings at 100%.

If you had a register dump from android with mics working, preferably
not in speaker mode, perhaps I could try to figure it out?

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.93 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-01 15:40:17

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Pavel Machek <[email protected]> [180401 13:20]:
> On Sat 2018-03-31 16:43:14, Tony Lindgren wrote:
> > * Pavel Machek <[email protected]> [180331 19:56]:
> > > On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > > > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > > > > the alsamixer settings but no mic. This is with cold boot with
> > > > > > droid4-kexecboot if that might make a difference, we may have
> > > > > > some register uninitialized somewhere. Any ideas?
> > > > >
> > > > > Ok, I was focusing on the speaker side.
> > > > >
> > > > > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > > > > should work, according to my notes, but not recently tested and not
> > > > > tested against real human.
> > > > >
> > > > > I'll attempt to test it, but something in my userland shuts down
> > > > > system just after boot 60% of time, which is rather annoying.
> > > >
> > > > Hmm. So I tried again, and setting Mic1 and back in the capture
> > > > settings crashed the modem. Bang, disconnected from the USB.
> > >
> > > Next try, and it worked this time.
> > >
> > > _Before the call_, set mode to Normal and then Call. Then go to
> > > capture, and set 100 100 Mic2 Mic1. Then place a call,
> > >
> > > AT+CFUN=1
> > > OK
> > > ATD6;
> >
> > No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
> > works, but ATD command on it just hangs the USB interface
> > and I have to reload phy-mapphone-mdm6600 to reset the
> > modem.
>
> Test call with real human worked (thanks to Rolf K.), I could hear him
> well but he reported call was very quiet. And that was with capture
> settings at 100%.

Maybe the volume also needs to be controlled at mdm6600 end.
I'm seeing some AT+CLVL=n with n being between [0-7] calls on
DLCI2 in my Android logcat logs.

> If you had a register dump from android with mics working, preferably
> not in speaker mode, perhaps I could try to figure it out?

OK here are four diffs against starting the phone app for regular
call, speaker call, and muted versions of them:

http://muru.com/linux/d4/cpcap/

Also, I'm connected over cdma right now, not 3g, but I doubt
that makes a difference for the microphone.

Regards,

Tony



2018-04-01 17:31:46

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Tony Lindgren <[email protected]> [180401 15:38]:
> * Pavel Machek <[email protected]> [180401 13:20]:
> > On Sat 2018-03-31 16:43:14, Tony Lindgren wrote:
> > > * Pavel Machek <[email protected]> [180331 19:56]:
> > > > On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > > > > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > > > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > > > > Cool :) Microphone still does not work for me.. I tried tweaking
> > > > > > > the alsamixer settings but no mic. This is with cold boot with
> > > > > > > droid4-kexecboot if that might make a difference, we may have
> > > > > > > some register uninitialized somewhere. Any ideas?
> > > > > >
> > > > > > Ok, I was focusing on the speaker side.
> > > > > >
> > > > > > alsamixer, tab to go to capture settings, set it to 37 37 Mic2 Mic1
> > > > > > should work, according to my notes, but not recently tested and not
> > > > > > tested against real human.
> > > > > >
> > > > > > I'll attempt to test it, but something in my userland shuts down
> > > > > > system just after boot 60% of time, which is rather annoying.
> > > > >
> > > > > Hmm. So I tried again, and setting Mic1 and back in the capture
> > > > > settings crashed the modem. Bang, disconnected from the USB.
> > > >
> > > > Next try, and it worked this time.
> > > >
> > > > _Before the call_, set mode to Normal and then Call. Then go to
> > > > capture, and set 100 100 Mic2 Mic1. Then place a call,
> > > >
> > > > AT+CFUN=1
> > > > OK
> > > > ATD6;
> > >
> > > No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
> > > works, but ATD command on it just hangs the USB interface
> > > and I have to reload phy-mapphone-mdm6600 to reset the
> > > modem.
> >
> > Test call with real human worked (thanks to Rolf K.), I could hear him
> > well but he reported call was very quiet. And that was with capture
> > settings at 100%.
>
> Maybe the volume also needs to be controlled at mdm6600 end.
> I'm seeing some AT+CLVL=n with n being between [0-7] calls on
> DLCI2 in my Android logcat logs.
>
> > If you had a register dump from android with mics working, preferably
> > not in speaker mode, perhaps I could try to figure it out?
>
> OK here are four diffs against starting the phone app for regular
> call, speaker call, and muted versions of them:
>
> http://muru.com/linux/d4/cpcap/
>
> Also, I'm connected over cdma right now, not 3g, but I doubt
> that makes a difference for the microphone.

Found it! Here's what I need to do over n_gsm:

ngsm 1 "AT+CFUN=1"
ngsm 1 "AT+CFUN?"
ngsm 2 "AT+EACC=3,0" # enable mic
ngsm 2 "AT+CLVL=4" # set speaker volume
ngsm 2 "AT+CMUT=0" # unmute mic
ngsm 1 "ATD${number}"
ngsm 1 "AT+CLCC" # list current calls
ngsm 2 "AT+NREC=1" # enable noise cancellation
ngsm 1 "AT+SCRN=0" # ??? not sure if this does anything

while [ 1 ]; do
date
ngsm 1 "AT+CLCC"
sleep 10
done

So speaker phone call works just fine, I just tested with a
human at the other end :)

Hmm let's hope all those also translate to some qmi calls.

Regards,

Tony

2018-04-01 23:19:19

by Tony Lindgren

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

* Tony Lindgren <[email protected]> [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

2018-04-02 15:08:51

by Mark Brown

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

On Wed, Mar 28, 2018 at 04:02:19PM +0200, Sebastian Reichel wrote:

> 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?

It's definitely pushing it towards being more useful to consider at
least in the short term, basically nobody ever did these TDM muxes since
usually you end up needing something more than just straight digital
data muxing (mixing for example) so things usually get routed through a
chip that can do more with the data.


Attachments:
(No filename) (650.00 B)
signature.asc (495.00 B)
Download all attachments

2018-04-02 15:52:16

by Dan Williams

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Sun, 2018-04-01 at 10:30 -0700, Tony Lindgren wrote:
> * Tony Lindgren <[email protected]> [180401 15:38]:
> > * Pavel Machek <[email protected]> [180401 13:20]:
> > > On Sat 2018-03-31 16:43:14, Tony Lindgren wrote:
> > > > * Pavel Machek <[email protected]> [180331 19:56]:
> > > > > On Sat 2018-03-31 21:46:16, Pavel Machek wrote:
> > > > > > On Sat 2018-03-31 21:19:39, Pavel Machek wrote:
> > > > > > > On Sat 2018-03-31 11:19:35, Tony Lindgren wrote:
> > > > > > > > Cool :) Microphone still does not work for me.. I tried
> > > > > > > > tweaking
> > > > > > > > the alsamixer settings but no mic. This is with cold
> > > > > > > > boot with
> > > > > > > > droid4-kexecboot if that might make a difference, we
> > > > > > > > may have
> > > > > > > > some register uninitialized somewhere. Any ideas?
> > > > > > >
> > > > > > > Ok, I was focusing on the speaker side.
> > > > > > >
> > > > > > > alsamixer, tab to go to capture settings, set it to 37 37
> > > > > > > Mic2 Mic1
> > > > > > > should work, according to my notes, but not recently
> > > > > > > tested and not
> > > > > > > tested against real human.
> > > > > > >
> > > > > > > I'll attempt to test it, but something in my userland
> > > > > > > shuts down
> > > > > > > system just after boot 60% of time, which is rather
> > > > > > > annoying.
> > > > > >
> > > > > > Hmm. So I tried again, and setting Mic1 and back in the
> > > > > > capture
> > > > > > settings crashed the modem. Bang, disconnected from the
> > > > > > USB.
> > > > >
> > > > > Next try, and it worked this time.
> > > > >
> > > > > _Before the call_, set mode to Normal and then Call. Then go
> > > > > to
> > > > > capture, and set 100 100 Mic2 Mic1. Then place a call,
> > > > >
> > > > > AT+CFUN=1
> > > > > OK
> > > > > ATD6;
> > > >
> > > > No luck with microphone here :( Using ttyUSB4, AT+CFUN=1
> > > > works, but ATD command on it just hangs the USB interface
> > > > and I have to reload phy-mapphone-mdm6600 to reset the
> > > > modem.
> > >
> > > Test call with real human worked (thanks to Rolf K.), I could
> > > hear him
> > > well but he reported call was very quiet. And that was with
> > > capture
> > > settings at 100%.
> >
> > Maybe the volume also needs to be controlled at mdm6600 end.
> > I'm seeing some AT+CLVL=n with n being between [0-7] calls on
> > DLCI2 in my Android logcat logs.
> >
> > > If you had a register dump from android with mics working,
> > > preferably
> > > not in speaker mode, perhaps I could try to figure it out?
> >
> > OK here are four diffs against starting the phone app for regular
> > call, speaker call, and muted versions of them:
> >
> > http://muru.com/linux/d4/cpcap/
> >
> > Also, I'm connected over cdma right now, not 3g, but I doubt
> > that makes a difference for the microphone.
>
> Found it! Here's what I need to do over n_gsm:
>
> ngsm 1 "AT+CFUN=1"
> ngsm 1 "AT+CFUN?"
> ngsm 2 "AT+EACC=3,0" # enable mic
> ngsm 2 "AT+CLVL=4" # set speaker volume
> ngsm 2 "AT+CMUT=0" # unmute mic

I tried to look through the QMI dumps we have in libqmi from 2013
(latest Qualcomm posted) and couldn't find anything to do with mic
control, speaker volume, or anything like that.

If the modem supports the AT service (which I think it does? Not
looking at the libqmi dumps right now) then it could potentially tunnel
these AT commands through QMI too.

Perhaps Qualcomm added something to the Voice service after 2013, or
perhaps there are other services that might control speaker/mic that we
don't have public dumps for yet though.

Dan

> ngsm 1 "ATD${number}"
> ngsm 1 "AT+CLCC" # list current calls
> ngsm 2 "AT+NREC=1" # enable noise cancellation
> ngsm 1 "AT+SCRN=0" # ??? not sure if this does anything
>
> while [ 1 ]; do
> date
> ngsm 1 "AT+CLCC"
> sleep 10
> done
>
> So speaker phone call works just fine, I just tested with a
> human at the other end :)
>
> Hmm let's hope all those also translate to some qmi calls.
>
> Regards,
>
> Tony

2018-04-02 15:59:25

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Dan Williams <[email protected]> [180402 15:51]:
> On Sun, 2018-04-01 at 10:30 -0700, Tony Lindgren wrote:
> > * Tony Lindgren <[email protected]> [180401 15:38]:
> > Found it! Here's what I need to do over n_gsm:
> >
> > ngsm 1 "AT+CFUN=1"
> > ngsm 1 "AT+CFUN?"
> > ngsm 2 "AT+EACC=3,0" # enable mic
> > ngsm 2 "AT+CLVL=4" # set speaker volume
> > ngsm 2 "AT+CMUT=0" # unmute mic
>
> I tried to look through the QMI dumps we have in libqmi from 2013
> (latest Qualcomm posted) and couldn't find anything to do with mic
> control, speaker volume, or anything like that.
>
> If the modem supports the AT service (which I think it does? Not
> looking at the libqmi dumps right now) then it could potentially tunnel
> these AT commands through QMI too.
>
> Perhaps Qualcomm added something to the Voice service after 2013, or
> perhaps there are other services that might control speaker/mic that we
> don't have public dumps for yet though.

OK thanks for checking. So probably only n_gsm channel 1 is for normal
Qualcomm at commands, and then channel 2 and others are commands
implemented by Motorola on the mdm6600.

I guess we'd have to add support for reading and writing to
/dev/gsmtty2 at least as it looks like these cannot be accessed
via /dev/ttyUSB4. Or at least I have not figured out any other
way to access them.

Regards,

Tony

2018-04-03 08:54:20

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCHv5,5/5] ARM: dts: omap4-droid4: add soundcard

Hi!

> > I think I should have the required options enabled...
> >
> > CONFIG_SND_OMAP_SOC=y
> > CONFIG_SND_OMAP_SOC_DMIC=y
> > CONFIG_SND_OMAP_SOC_MCBSP=y
> > CONFIG_SND_OMAP_SOC_MCPDM=y
> > CONFIG_SND_OMAP_SOC_HDMI_AUDIO=y
>
> That's the SoC (OMAP) side.
>
> > # CONFIG_SND_OMAP_SOC_RX51 is not set
> > # CONFIG_SND_OMAP_SOC_N9 is not set
> > CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y
> > CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=y
>
> That's not needed (but does not hurt). The Droid 4
> has no TWL companion chip and uses CPCAP instead.

Umm. AFAICT CONFIG_SND_OMAP_SOC_MCBSP=y can not be selected without
selecting one of the other options... right?

Seems like bug in Kconfig.

Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (860.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-03 15:06:37

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Tony Lindgren <[email protected]> [180402 15:59]:
> * Dan Williams <[email protected]> [180402 15:51]:
> > On Sun, 2018-04-01 at 10:30 -0700, Tony Lindgren wrote:
> > > * Tony Lindgren <[email protected]> [180401 15:38]:
> > > Found it! Here's what I need to do over n_gsm:
> > >
> > > ngsm 1 "AT+CFUN=1"
> > > ngsm 1 "AT+CFUN?"
> > > ngsm 2 "AT+EACC=3,0" # enable mic
> > > ngsm 2 "AT+CLVL=4" # set speaker volume
> > > ngsm 2 "AT+CMUT=0" # unmute mic
> >
> > I tried to look through the QMI dumps we have in libqmi from 2013
> > (latest Qualcomm posted) and couldn't find anything to do with mic
> > control, speaker volume, or anything like that.
> >
> > If the modem supports the AT service (which I think it does? Not
> > looking at the libqmi dumps right now) then it could potentially tunnel
> > these AT commands through QMI too.
> >
> > Perhaps Qualcomm added something to the Voice service after 2013, or
> > perhaps there are other services that might control speaker/mic that we
> > don't have public dumps for yet though.
>
> OK thanks for checking. So probably only n_gsm channel 1 is for normal
> Qualcomm at commands, and then channel 2 and others are commands
> implemented by Motorola on the mdm6600.
>
> I guess we'd have to add support for reading and writing to
> /dev/gsmtty2 at least as it looks like these cannot be accessed
> via /dev/ttyUSB4. Or at least I have not figured out any other
> way to access them.

Hmm or maybe there is some way to select where qmi to tunnels the
AT commands to? Some kind of channel type paramenter like n_gsm
has?

Anyways, for trying to figure out things for alsamixer, I tested
that ngsm 2 "AT+EACC=3,0" is not related to cpcap audio register
settings and the mic is enabled during the call with Pavel's patch
with alsamixer "Mode" set to either "Call" or "Normal". Also speaker
keeps working during the call toggling between "Call" and "Normal".
"Voice" in alsamixer does also control the speaker volume during
the call. And setting the second "Speaker" from "Voice" to "HiFi"
mutes the speaker.

Then alsamixer capture settings for "Mic2" do change the mic gain
as expected, and setting "Right" to "Off" mutes the mic. And then
setting "Left" to "Mic 2" turns on the mic again.

So my guess is that ngsm 2 "AT+EACC=3,0" and ngsm 2 "AT+CLVL=4"
might control some external amp over the mdm6600 gpio pins?
With "AT+CLVL" values being 0 7 it sounds like 3 gpios for that?

Regards,

Tony

2018-04-03 15:52:05

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

Hi!

> > OK thanks for checking. So probably only n_gsm channel 1 is for normal
> > Qualcomm at commands, and then channel 2 and others are commands
> > implemented by Motorola on the mdm6600.
> >
> > I guess we'd have to add support for reading and writing to
> > /dev/gsmtty2 at least as it looks like these cannot be accessed
> > via /dev/ttyUSB4. Or at least I have not figured out any other
> > way to access them.
>
> Hmm or maybe there is some way to select where qmi to tunnels the
> AT commands to? Some kind of channel type paramenter like n_gsm
> has?
>
> Anyways, for trying to figure out things for alsamixer, I tested
> that ngsm 2 "AT+EACC=3,0" is not related to cpcap audio register
> settings and the mic is enabled during the call with Pavel's patch
> with alsamixer "Mode" set to either "Call" or "Normal". Also speaker
> keeps working during the call toggling between "Call" and "Normal".
> "Voice" in alsamixer does also control the speaker volume during
> the call. And setting the second "Speaker" from "Voice" to "HiFi"
> mutes the speaker.

Take a look at the patch. Selecting "call" does something at hardware
level, selecting "normal" is a nop.

Sorry for confusion.

Yes, that patch needs more work.

Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2018-04-03 19:45:51

by Tony Lindgren

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

* Pavel Machek <[email protected]> [180403 15:51]:
> Hi!
>
> > > OK thanks for checking. So probably only n_gsm channel 1 is for normal
> > > Qualcomm at commands, and then channel 2 and others are commands
> > > implemented by Motorola on the mdm6600.
> > >
> > > I guess we'd have to add support for reading and writing to
> > > /dev/gsmtty2 at least as it looks like these cannot be accessed
> > > via /dev/ttyUSB4. Or at least I have not figured out any other
> > > way to access them.
> >
> > Hmm or maybe there is some way to select where qmi to tunnels the
> > AT commands to? Some kind of channel type paramenter like n_gsm
> > has?
> >
> > Anyways, for trying to figure out things for alsamixer, I tested
> > that ngsm 2 "AT+EACC=3,0" is not related to cpcap audio register
> > settings and the mic is enabled during the call with Pavel's patch
> > with alsamixer "Mode" set to either "Call" or "Normal". Also speaker
> > keeps working during the call toggling between "Call" and "Normal".
> > "Voice" in alsamixer does also control the speaker volume during
> > the call. And setting the second "Speaker" from "Voice" to "HiFi"
> > mutes the speaker.
>
> Take a look at the patch. Selecting "call" does something at hardware
> level, selecting "normal" is a nop.
>
> Sorry for confusion.
>
> Yes, that patch needs more work.

OK that explains why the speaker keeps working then :)

Regards,

Tony

2018-04-03 22:12:38

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

Hi!

> > If you had a register dump from android with mics working, preferably
> > not in speaker mode, perhaps I could try to figure it out?
>
> OK here are four diffs against starting the phone app for regular
> call, speaker call, and muted versions of them:
>
> http://muru.com/linux/d4/cpcap/
>
> Also, I'm connected over cdma right now, not 3g, but I doubt
> that makes a difference for the microphone.

Thanks!

When I apply register settings directly, I indeed get working "normal"
call working. Good. Diff for illustration is below. Clearly needs some
improvements.

And it shows that alsa mixers are expected to be simple and obvious on
D4 -- they just do not work.

Current version of phone gui is at
https://github.com/pavelmachek/unicsy_demo

- ofono interface should be usable
- AT commands need a lot more work, and they'll probably never work
nicely in this design. They are just a temporary hack.

(ouch, and it should be rewritten, in Vala or better Rust...)
Pavel

commit 06acc26c318558ed6a50b5a22afffeb9abbe7553
Author: Pavel <[email protected]>
Date: Wed Apr 4 00:04:34 2018 +0200

Add support for "normal" (not handsfree) call.

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 7aaa4db..59c02b7 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -331,7 +331,7 @@ static const char * const cpcap_in_left_mux_texts[] = {
};

static const char * const cpcap_mode_texts[] = {
- "Normal", "Call"
+ "Normal", "Handsfree", "Call",
};


@@ -464,25 +464,11 @@ static int cpcap_mode_get_enum(struct snd_kcontrol *kcontrol,
return 0;
}

-static int cpcap_mode_put_enum(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int enable_call(struct cpcap_audio *cpcap, int on)
{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int muxval = ucontrol->value.enumerated.item[0];
- unsigned int mask = BIT(e->shift_l);
int err;
-
- printk("Requested mode %d\n", muxval);
-
- mode = muxval;
-
- switch (muxval) {
- case 1:
-
+ unsigned long mask;
+
err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
0xffff, 0x0025); // OK
if (err)
@@ -516,6 +502,56 @@ static int cpcap_mode_put_enum(struct snd_kcontrol *kcontrol,
0x0400, 0x0400);
if (err)
printk("error #1\n");
+
+ return 0;
+out:
+ printk("Error!\n");
+ return -EIO;
+}
+
+static int cpcap_mode_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct cpcap_audio *cpcap = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int muxval = ucontrol->value.enumerated.item[0];
+ unsigned int mask = BIT(e->shift_l);
+ int err;
+
+ printk("Requested mode %d\n", muxval);
+
+ mode = muxval;
+
+ switch (muxval) {
+ case 1:
+ enable_call(cpcap, 1);
+ break;
+ case 2:
+ enable_call(cpcap, 1);
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+ 0xffff, 0x0cc6);
+ if (err)
+ goto out;
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXMP,
+ 0xffff, 0x0673);
+ if (err)
+ goto out;
+
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
+ 0xffff, 0x0001);
+ if (err)
+ goto out;
+
+ err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+ 0xffff, 0x0601);
+ if (err)
+ goto out;

default:
break;

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (3.94 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-06 12:06:44

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

Hi!

> OK that explains why the speaker keeps working then :)

Ok, I pushed new version of unicsy_demo.

It now sends & receives sms and you can call & receive call. Tone from
linphone is used for incoming call. User interface and code is
slightly weird, as ofono was -- and still is -- meant as a backend.


Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (475.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-06 12:25:33

by Merlijn Wajer

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

Hi,

On 06/04/18 14:04, Pavel Machek wrote:
> Hi!
>
>> OK that explains why the speaker keeps working then :)
>
> Ok, I pushed new version of unicsy_demo.
>
> It now sends & receives sms and you can call & receive call. Tone from
> linphone is used for incoming call. User interface and code is
> slightly weird, as ofono was -- and still is -- meant as a backend.

Great news, can't wait to try it.

Did you modify ofono beyond the patches you have already posted? And
what version of ofono was that for?

Cheers,
Merlijn


Attachments:
signature.asc (235.00 B)
OpenPGP digital signature

2018-04-06 12:46:38

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Fri 2018-04-06 14:23:46, Merlijn Wajer wrote:
> Hi,
>
> On 06/04/18 14:04, Pavel Machek wrote:
> > Hi!
> >
> >> OK that explains why the speaker keeps working then :)
> >
> > Ok, I pushed new version of unicsy_demo.
> >
> > It now sends & receives sms and you can call & receive call. Tone from
> > linphone is used for incoming call. User interface and code is
> > slightly weird, as ofono was -- and still is -- meant as a backend.
>
> Great news, can't wait to try it.
>
> Did you modify ofono beyond the patches you have already posted? And
> what version of ofono was that for?

Forget ofono for now. I modified ofone to issue at commands
directly. It is .. a hack, but should be good enough for testing.

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (912.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-06 22:06:38

by Pavel Machek

[permalink] [raw]
Subject: Re: call/normal switch was Re: omap4-droid4: voice call support was

On Fri 2018-04-06 14:23:46, Merlijn Wajer wrote:
> Hi,
>
> On 06/04/18 14:04, Pavel Machek wrote:
> > Hi!
> >
> >> OK that explains why the speaker keeps working then :)
> >
> > Ok, I pushed new version of unicsy_demo.
> >
> > It now sends & receives sms and you can call & receive call. Tone from
> > linphone is used for incoming call. User interface and code is
> > slightly weird, as ofono was -- and still is -- meant as a backend.
>
> Great news, can't wait to try it.

Oh btw ... if you need any help just ask. unicsy_demo needs to be
symlinked to /usr/share/unicsy.

If you could make notes of any problems you encounter and any packages
you'll need to install, that would be nice -- it would be good to
create README with installation instructions.

Good luck,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (954.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-07 08:13:30

by Pavel Machek

[permalink] [raw]
Subject: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

Hi!

It seems qmicli can be used while unicsy_demo/ofone talks to the modem
using the AT commands.

So I could do:

qmicli -d /dev/cdc-wdm0 --wds-follow-network --wds-start-network=apn=internet.t-mobile.cz
route del default
sudo ifconfig wwan0 up
dhclient wwan0

to get GPRS/UMTS connection. AT commands still work.

Does anyone have any idea what to do to get the GPS to work?

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (550.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-07 12:25:55

by Pavel Machek

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Sat 2018-04-07 10:10:00, Pavel Machek wrote:
> Hi!
>
> It seems qmicli can be used while unicsy_demo/ofone talks to the modem
> using the AT commands.
>
> So I could do:
>
> qmicli -d /dev/cdc-wdm0 --wds-follow-network --wds-start-network=apn=internet.t-mobile.cz
> route del default
> sudo ifconfig wwan0 up
> dhclient wwan0
>
> to get GPRS/UMTS connection. AT commands still work.
>
> Does anyone have any idea what to do to get the GPS to work?

Got that to work.

I installed modemmanager -- unfortunately that claims ttyUSB4 so it
breaks voice/sms -- but then

mmcli -m 0 --enable
mmcli -m 0 --location-enable-gps-nmea
watch -n .3 sudo mmcli -m 0 --location-get-gps-nmea

...can be used to get GPS data. Droid4 seems to have rather bad GPS,
so you should probably put it near window for testing.

Is there way to grab data from modemmanager and feed it to gpsd, so
that normal applications can access gps? I don't see easy way.

I tried --location-enable-gps-unmanaged , but that did not work for
me.

Is modemmanager enabling GPS, or is it talking to libqmi to do that?
The code is quite confusing to me...

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.30 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-08 02:48:22

by Dan Williams

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> On Sat 2018-04-07 10:10:00, Pavel Machek wrote:
> > Hi!
> >
> > It seems qmicli can be used while unicsy_demo/ofone talks to the
> > modem
> > using the AT commands.
> >
> > So I could do:
> >
> > qmicli -d /dev/cdc-wdm0 --wds-follow-network --wds-start-
> > network=apn=internet.t-mobile.cz
> > route del default
> > sudo ifconfig wwan0 up
> > dhclient wwan0
> >
> > to get GPRS/UMTS connection. AT commands still work.
> >
> > Does anyone have any idea what to do to get the GPS to work?
>
> Got that to work.
>
> I installed modemmanager -- unfortunately that claims ttyUSB4 so it
> breaks voice/sms -- but then

It shouldn't break SMS since MM will do SMS via QMI, but yeah for now
it'll break voice because that would happen via QMI too, and we haven't
implemented voice for QMI yet.

--help-messaging
--help-sms

Also available via D-Bus of course.

> mmcli -m 0 --enable
> mmcli -m 0 --location-enable-gps-nmea
> watch -n .3 sudo mmcli -m 0 --location-get-gps-nmea
>
> ...can be used to get GPS data. Droid4 seems to have rather bad GPS,
> so you should probably put it near window for testing.
>
> Is there way to grab data from modemmanager and feed it to gpsd, so
> that normal applications can access gps? I don't see easy way.
>
> I tried --location-enable-gps-unmanaged , but that did not work for
> me.

That requires a TTY that would spit out the GPS data; in this mode MM
only sends the start/stop commands, and what comes out the GPS TTY is
undefined (at least by MM).

So unless you know that one of the 6600's TTYs does GPS and in what
format it does GPS, then no.

Doesn't --location-get-gps-nmea work for you? That will spit out the
latest NMEA traces MM gets from the modem, if it supports NMEA. I
believe --location-status will tell you what methods MM supports with
the modem.

Also available via D-Bus of course.

> Is modemmanager enabling GPS, or is it talking to libqmi to do that?
> The code is quite confusing to me...

Yes. When the modem is driven with QMI, then all the data comes from
QMI. For other modems (like Huawei HiLink and Gobi 1000) the enabling
commands are done via AT on the main command port and then one of the
TTYs starts spewing out NMEA.

Dan

2018-04-08 08:01:13

by Pavel Machek

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

Hi!

> > mmcli -m 0 --enable
> > mmcli -m 0 --location-enable-gps-nmea
> > watch -n .3 sudo mmcli -m 0 --location-get-gps-nmea
> >
> > ...can be used to get GPS data. Droid4 seems to have rather bad GPS,
> > so you should probably put it near window for testing.
> >
> > Is there way to grab data from modemmanager and feed it to gpsd, so
> > that normal applications can access gps? I don't see easy way.
> >
> > I tried --location-enable-gps-unmanaged , but that did not work for
> > me.
>
> That requires a TTY that would spit out the GPS data; in this mode MM
> only sends the start/stop commands, and what comes out the GPS TTY is
> undefined (at least by MM).
>
> So unless you know that one of the 6600's TTYs does GPS and in what
> format it does GPS, then no.
>
> Doesn't --location-get-gps-nmea work for you? That will spit out the
> latest NMEA traces MM gets from the modem, if it supports NMEA. I
> believe --location-status will tell you what methods MM supports with
> the modem.

Yes, --location-get-gps-nmea works for me.

I guess one way forward would be to implement --location-get-gps-nmea
support for qmicli, and use that?

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.33 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-09 03:18:48

by Dan Williams

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Sun, 2018-04-08 at 09:41 +0200, Pavel Machek wrote:
> Hi!
>
> > > mmcli -m 0 --enable
> > > mmcli -m 0 --location-enable-gps-nmea
> > > watch -n .3 sudo mmcli -m 0 --location-get-gps-nmea
> > >
> > > ...can be used to get GPS data. Droid4 seems to have rather bad
> > > GPS,
> > > so you should probably put it near window for testing.
> > >
> > > Is there way to grab data from modemmanager and feed it to gpsd,
> > > so
> > > that normal applications can access gps? I don't see easy way.
> > >
> > > I tried --location-enable-gps-unmanaged , but that did not work
> > > for
> > > me.
> >
> > That requires a TTY that would spit out the GPS data; in this mode
> > MM
> > only sends the start/stop commands, and what comes out the GPS TTY
> > is
> > undefined (at least by MM).
> >
> > So unless you know that one of the 6600's TTYs does GPS and in what
> > format it does GPS, then no.
> >
> > Doesn't --location-get-gps-nmea work for you? That will spit out
> > the
> > latest NMEA traces MM gets from the modem, if it supports NMEA. I
> > believe --location-status will tell you what methods MM supports
> > with
> > the modem.
>
> Yes, --location-get-gps-nmea works for me.
>
> I guess one way forward would be to implement --location-get-gps-nmea
> support for qmicli, and use that?

Yeah, libqmi already has the necessary bits but it's not plumbed
through to qmicli. Note that qmicli is a straight interface to QMI and
doesn't try to impose abstractions on anything, so you wouldn't get --
location-get-gps-nmea, but you'd instead be working directly with the
QMI PDS (older) and/or LOC (newer) service commands.

Dan

2018-04-09 14:13:58

by Tony Lindgren

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

* Dan Williams <[email protected]> [180408 02:46]:
> On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > I tried --location-enable-gps-unmanaged , but that did not work for
> > me.
>
> That requires a TTY that would spit out the GPS data; in this mode MM
> only sends the start/stop commands, and what comes out the GPS TTY is
> undefined (at least by MM).
>
> So unless you know that one of the 6600's TTYs does GPS and in what
> format it does GPS, then no.

There should be a NMEA port within the unknown port range ttyUSB[123].

Is there some easy way to enable --location-enable-gps-unmanaged for
testing so I can check if GPS gets enabled for one of the ports?

Regards,

Tony

2018-04-09 15:57:43

by Dan Williams

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Mon, 2018-04-09 at 07:08 -0700, Tony Lindgren wrote:
> * Dan Williams <[email protected]> [180408 02:46]:
> > On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > > I tried --location-enable-gps-unmanaged , but that did not work
> > > for
> > > me.
> >
> > That requires a TTY that would spit out the GPS data; in this mode
> > MM
> > only sends the start/stop commands, and what comes out the GPS TTY
> > is
> > undefined (at least by MM).
> >
> > So unless you know that one of the 6600's TTYs does GPS and in what
> > format it does GPS, then no.
>
> There should be a NMEA port within the unknown port range
> ttyUSB[123].
>
> Is there some easy way to enable --location-enable-gps-unmanaged for
> testing so I can check if GPS gets enabled for one of the ports?

Not all modems support all of the ModemManager location options;
-unmanaged is only for devices that support sending the data to a
separate port and for which we know the commands to do that.

It looks like QMI has a way to direct the output to a specific device:

// Enum to describe QMI PDS Output Devices
enum eQMIPDSOutputDevices:UINT8
{
eQMIPDSOutputDevices_NoneDisabled = 0,
eQMIPDSOutputDevices_USB = 1,
eQMIPDSOutputDevices_UART1 = 2,
eQMIPDSOutputDevices_UART2 = 3,
eQMIPDSOutputDevices_SharedMemory = 4,
};

so we could add support for that to libqmi and then to ModemManager,
which could help implement --location-enable-gps-unmanaged on alternate
ports.

But what might be simpler is implementing something like the "QMI GPS
proxy" that already exists, but for ModemManager or libqmi directly.
That way you can use QMI and get known formatting of the output data,
but proxy it to a normal-looking NMEA tty? Instead of trying to figure
out which TTY/UART/etc the information comes out of for each specific
device and somehow encoding that into the platform. We know what the
QMI ports are already, that's easy. We don't know what all the TTYs
are for every given modem and hardcoding that info somewhere is error-
prone and hard to keep up with.

Dan

2018-04-09 20:25:05

by Pavel Machek

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Mon 2018-04-09 07:08:47, Tony Lindgren wrote:
> * Dan Williams <[email protected]> [180408 02:46]:
> > On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > > I tried --location-enable-gps-unmanaged , but that did not work for
> > > me.
> >
> > That requires a TTY that would spit out the GPS data; in this mode MM
> > only sends the start/stop commands, and what comes out the GPS TTY is
> > undefined (at least by MM).
> >
> > So unless you know that one of the 6600's TTYs does GPS and in what
> > format it does GPS, then no.
>
> There should be a NMEA port within the unknown port range ttyUSB[123].
>
> Is there some easy way to enable --location-enable-gps-unmanaged for
> testing so I can check if GPS gets enabled for one of the ports?

In the meantime, I got GPS to work :-).

I modified qmicli to pipe NMEA data to stdout, which should be enough.

But yes, directly exposing NMEA data on ttyGSM? would be even nicer.

Thanks,

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.10 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-10 11:03:51

by Pavel Machek

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Mon 2018-04-09 07:08:47, Tony Lindgren wrote:
> * Dan Williams <[email protected]> [180408 02:46]:
> > On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > > I tried --location-enable-gps-unmanaged , but that did not work for
> > > me.
> >
> > That requires a TTY that would spit out the GPS data; in this mode MM
> > only sends the start/stop commands, and what comes out the GPS TTY is
> > undefined (at least by MM).
> >
> > So unless you know that one of the 6600's TTYs does GPS and in what
> > format it does GPS, then no.
>
> There should be a NMEA port within the unknown port range ttyUSB[123].
>
> Is there some easy way to enable --location-enable-gps-unmanaged for
> testing so I can check if GPS gets enabled for one of the ports?

This should be userful for testing:

Just pass --pds-start-gps and you should get NMEA on stdout.

Cleanup does _not_ work properly, so it will fail if you run it too
many times.

Pavel

diff --git a/src/qmicli/Makefile.am b/src/qmicli/Makefile.am
index eb63fa7..2c5e935 100644
--- a/src/qmicli/Makefile.am
+++ b/src/qmicli/Makefile.am
@@ -42,6 +42,7 @@ qmicli_SOURCES = \
qmicli-pdc.c \
qmicli-uim.c \
qmicli-wms.c \
+ qmicli-pds.c \
qmicli-wda.c \
qmicli-voice.c \
qmicli-charsets.c \
diff --git a/src/qmicli/qmicli-loc.c b/src/qmicli/qmicli-loc.c
new file mode 100644
index 0000000..e69de29
diff --git a/src/qmicli/qmicli-pds.c b/src/qmicli/qmicli-pds.c
new file mode 100644
index 0000000..f21ba2e
--- /dev/null
+++ b/src/qmicli/qmicli-pds.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * qmicli -- Command line interface to control QMI devices
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2015-2017 Aleksander Morgado <[email protected]>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libqmi-glib.h>
+
+#include "qmicli.h"
+#include "qmicli-helpers.h"
+
+/* Context */
+typedef struct {
+ QmiDevice *device;
+ QmiClientPds *client;
+ GCancellable *cancellable;
+} Context;
+static Context *ctx;
+
+/* Options */
+static gboolean get_supported_messages_flag;
+static gboolean reset_flag;
+static gboolean noop_flag;
+static gboolean start_flag;
+
+static GOptionEntry entries[] = {
+ { "pds-start-gps", 0, 0, G_OPTION_ARG_NONE, &start_flag,
+ "Start gps",
+ NULL
+ },
+
+ { NULL }
+};
+
+GOptionGroup *
+qmicli_pds_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ group = g_option_group_new ("pds",
+ "PDS options",
+ "Show Wireless Messaging Service options",
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
+
+gboolean
+qmicli_pds_options_enabled (void)
+{
+ static guint n_actions = 0;
+ static gboolean checked = FALSE;
+
+ if (checked)
+ return !!n_actions;
+
+ n_actions = (get_supported_messages_flag +
+ reset_flag +
+ noop_flag +
+ start_flag);
+
+ if (n_actions > 1) {
+ g_printerr ("error: too many PDS actions requested\n");
+ exit (EXIT_FAILURE);
+ }
+
+ checked = TRUE;
+ return !!n_actions;
+}
+
+#if 0
+static void
+context_free (Context *context)
+{
+ if (!context)
+ return;
+
+ if (context->client)
+ g_object_unref (context->client);
+ g_object_unref (context->cancellable);
+ g_object_unref (context->device);
+ g_slice_free (Context, context);
+}
+
+static void
+operation_shutdown (gboolean operation_status)
+{
+ /* Cleanup context and finish async operation */
+ context_free (ctx);
+ qmicli_async_operation_done (operation_status, FALSE);
+}
+#endif
+
+static void
+ser_location_ready (QmiClientPds *client,
+ GAsyncResult *res,
+ GTask *task);
+
+static void
+location_event_report_indication_cb (QmiClientPds *client,
+ QmiIndicationPdsEventReportOutput *output,
+ void *self)
+{
+ QmiPdsPositionSessionStatus session_status;
+ const gchar *nmea;
+
+ if (qmi_indication_pds_event_report_output_get_position_session_status (
+ output,
+ &session_status,
+ NULL)) {
+ printf ("[GPS] session status changed: '%s'",
+ qmi_pds_position_session_status_get_string (session_status));
+ }
+
+ if (qmi_indication_pds_event_report_output_get_nmea_position (
+ output,
+ &nmea,
+ NULL)) {
+ printf ("%s", nmea);
+ }
+}
+
+static void
+gather_nmea(GTask *task)
+{
+ QmiMessagePdsSetEventReportInput *input;
+
+ /* Only gather standard NMEA traces */
+ input = qmi_message_pds_set_event_report_input_new ();
+ qmi_message_pds_set_event_report_input_set_nmea_position_reporting (input, TRUE, NULL);
+ qmi_client_pds_set_event_report (
+ ctx->client,
+ input,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)ser_location_ready,
+ task);
+ qmi_message_pds_set_event_report_input_unref (input);
+
+}
+
+static void
+ser_location_ready (QmiClientPds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ QmiMessagePdsSetEventReportOutput *output = NULL;
+ GError *error = NULL;
+
+ output = qmi_client_pds_set_event_report_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!qmi_message_pds_set_event_report_output_get_result (output, &error)) {
+ g_prefix_error (&error, "Couldn't set event report: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ qmi_message_pds_set_event_report_output_unref (output);
+ return;
+ }
+
+ qmi_message_pds_set_event_report_output_unref (output);
+
+ g_signal_connect (client,
+ "event-report",
+ G_CALLBACK (location_event_report_indication_cb),
+ NULL);
+}
+
+static void
+auto_tracking_state_start_ready (QmiClientPds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ QmiMessagePdsSetAutoTrackingStateOutput *output = NULL;
+ GError *error = NULL;
+
+ output = qmi_client_pds_set_auto_tracking_state_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!qmi_message_pds_set_auto_tracking_state_output_get_result (output, &error)) {
+ if (!g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_NO_EFFECT)) {
+ g_prefix_error (&error, "Couldn't set auto-tracking state: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ qmi_message_pds_set_auto_tracking_state_output_unref (output);
+ return;
+ }
+ g_error_free (error);
+ printf("no matches: was already enabled?\n");
+ }
+ qmi_message_pds_set_auto_tracking_state_output_unref (output);
+ gather_nmea(task);
+}
+
+
+static void
+gps_service_state_start_ready (QmiClientPds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ QmiMessagePdsSetAutoTrackingStateInput *input;
+ QmiMessagePdsSetGpsServiceStateOutput *output = NULL;
+ GError *error = NULL;
+
+ output = qmi_client_pds_set_gps_service_state_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!qmi_message_pds_set_gps_service_state_output_get_result (output, &error)) {
+ if (!g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_NO_EFFECT)) {
+ g_prefix_error (&error, "Couldn't set GPS service state: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ qmi_message_pds_set_gps_service_state_output_unref (output);
+ return;
+ }
+ g_error_free (error);
+ }
+ qmi_message_pds_set_gps_service_state_output_unref (output);
+
+ /* Enable auto-tracking for a continuous fix */
+ input = qmi_message_pds_set_auto_tracking_state_input_new ();
+ qmi_message_pds_set_auto_tracking_state_input_set_state (input, TRUE, NULL);
+ qmi_client_pds_set_auto_tracking_state (
+ ctx->client,
+ input,
+ 10,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)auto_tracking_state_start_ready,
+ task);
+ qmi_message_pds_set_auto_tracking_state_input_unref (input);
+}
+
+
+void
+qmicli_pds_run (QmiDevice *device,
+ QmiClientPds *client,
+ GCancellable *cancellable)
+{
+ /* Initialize context */
+ ctx = g_slice_new (Context);
+ ctx->device = g_object_ref (device);
+ ctx->client = g_object_ref (client);
+ ctx->cancellable = g_object_ref (cancellable);
+
+ if (start_flag) {
+ QmiMessagePdsSetGpsServiceStateInput *input;
+
+ input = qmi_message_pds_set_gps_service_state_input_new ();
+ qmi_message_pds_set_gps_service_state_input_set_state (input, TRUE, NULL);
+ qmi_client_pds_set_gps_service_state (
+ ctx->client,
+ input,
+ 10,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gps_service_state_start_ready,
+ ctx);
+ qmi_message_pds_set_gps_service_state_input_unref (input);
+ printf("GPS started?\n");
+ return;
+ }
+
+ if (1) { // run_flag)
+ g_signal_connect (client,
+ "event-report",
+ G_CALLBACK (location_event_report_indication_cb),
+ NULL);
+ }
+
+ g_warn_if_reached ();
+}
diff --git a/src/qmicli/qmicli.c b/src/qmicli/qmicli.c
index fecae8d..32d1052 100644
--- a/src/qmicli/qmicli.c
+++ b/src/qmicli/qmicli.c
@@ -366,6 +366,9 @@ allocate_client_ready (QmiDevice *dev,
case QMI_SERVICE_WMS:
qmicli_wms_run (dev, QMI_CLIENT_WMS (client), cancellable);
return;
+ case QMI_SERVICE_PDS:
+ qmicli_pds_run (dev, QMI_CLIENT_PDS (client), cancellable);
+ return;
case QMI_SERVICE_WDA:
qmicli_wda_run (dev, QMI_CLIENT_WDA (client), cancellable);
return;
@@ -719,6 +722,12 @@ parse_actions (void)
actions_enabled++;
}

+ /* PDS options? */
+ if (qmicli_pds_options_enabled ()) {
+ service = QMI_SERVICE_PDS;
+ actions_enabled++;
+ }
+
/* WDA options? */
if (qmicli_wda_options_enabled ()) {
service = QMI_SERVICE_WDA;
@@ -769,6 +778,8 @@ int main (int argc, char **argv)
g_option_context_add_group (context,
qmicli_uim_get_option_group ());
g_option_context_add_group (context,
+ qmicli_pds_get_option_group ());
+ g_option_context_add_group (context,
qmicli_wms_get_option_group ());
g_option_context_add_group (context,
qmicli_wda_get_option_group ());
diff --git a/src/qmicli/qmicli.h b/src/qmicli/qmicli.h
index 7db7905..0986b66 100644
--- a/src/qmicli/qmicli.h
+++ b/src/qmicli/qmicli.h
@@ -69,6 +69,14 @@ void qmicli_uim_run (QmiDevice *device,
QmiClientUim *client,
GCancellable *cancellable);

+
+/* PDS group */
+GOptionGroup *qmicli_pds_get_option_group (void);
+gboolean qmicli_pds_options_enabled (void);
+void qmicli_pds_run (QmiDevice *device,
+ QmiClientPds *client,
+ GCancellable *cancellable);
+
/* WMS group */
GOptionGroup *qmicli_wms_get_option_group (void);
gboolean qmicli_wms_options_enabled (void);

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (14.31 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2018-04-10 13:57:11

by Tony Lindgren

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

* Pavel Machek <[email protected]> [180410 11:00]:
> On Mon 2018-04-09 07:08:47, Tony Lindgren wrote:
> > * Dan Williams <[email protected]> [180408 02:46]:
> > > On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > > > I tried --location-enable-gps-unmanaged , but that did not work for
> > > > me.
> > >
> > > That requires a TTY that would spit out the GPS data; in this mode MM
> > > only sends the start/stop commands, and what comes out the GPS TTY is
> > > undefined (at least by MM).
> > >
> > > So unless you know that one of the 6600's TTYs does GPS and in what
> > > format it does GPS, then no.
> >
> > There should be a NMEA port within the unknown port range ttyUSB[123].
> >
> > Is there some easy way to enable --location-enable-gps-unmanaged for
> > testing so I can check if GPS gets enabled for one of the ports?
>
> This should be userful for testing:
>
> Just pass --pds-start-gps and you should get NMEA on stdout.

Hmm maybe also try to check if enabling the GPS this way starts
printing something out of /dev/ttyUSB[123]?

Regards,

Tony

2018-04-11 11:47:02

by Pavel Machek

[permalink] [raw]
Subject: Re: simultaneous voice/data works (was Re: call/normal switch was Re: omap4-droid4: voice call support was)

On Tue 2018-04-10 06:50:29, Tony Lindgren wrote:
> * Pavel Machek <[email protected]> [180410 11:00]:
> > On Mon 2018-04-09 07:08:47, Tony Lindgren wrote:
> > > * Dan Williams <[email protected]> [180408 02:46]:
> > > > On Sat, 2018-04-07 at 14:22 +0200, Pavel Machek wrote:
> > > > > I tried --location-enable-gps-unmanaged , but that did not work for
> > > > > me.
> > > >
> > > > That requires a TTY that would spit out the GPS data; in this mode MM
> > > > only sends the start/stop commands, and what comes out the GPS TTY is
> > > > undefined (at least by MM).
> > > >
> > > > So unless you know that one of the 6600's TTYs does GPS and in what
> > > > format it does GPS, then no.
> > >
> > > There should be a NMEA port within the unknown port range ttyUSB[123].
> > >
> > > Is there some easy way to enable --location-enable-gps-unmanaged for
> > > testing so I can check if GPS gets enabled for one of the ports?
> >
> > This should be userful for testing:
> >
> > Just pass --pds-start-gps and you should get NMEA on stdout.
>
> Hmm maybe also try to check if enabling the GPS this way starts
> printing something out of /dev/ttyUSB[123]?

No, I did not find anything there :-(.

This combination seems to give me working gps:

sudo src/qmicli/qmicli -d /dev/cdc-wdm0 --pds-start-gps | nc -u 127.0.0.1 5000

/usr/sbin/gpsd -ND 4 udp://127.0.0.1:5000

Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.53 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments