linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints
       [not found] <20200614202411.27843-1-xc-racer2@live.ca>
@ 2020-06-14 20:24 ` Jonathan Bakker
  2020-06-15 12:40   ` Mark Brown
  2020-06-15 23:39   ` Mark Brown
  2020-06-14 20:24 ` [PATCH 2/3] dt-bindings: sound: Add bindings for Samsung Aries audio complex Jonathan Bakker
  2020-06-14 20:24 ` [PATCH 3/3] ASoC: samsung: Add driver for Aries boards Jonathan Bakker
  2 siblings, 2 replies; 5+ messages in thread
From: Jonathan Bakker @ 2020-06-14 20:24 UTC (permalink / raw)
  To: krzk, sbkim73, s.nawrocki, lgirdwood, broonie, perex, tiwai,
	alsa-devel, linux-kernel, robh+dt, devicetree
  Cc: Jonathan Bakker

The wm8994 exposes several inputs and outputs that can be used by
machine drivers in their routing.  Add them to the documention so
they don't have been duplicated in any machine drivers bindings.

Signed-off-by: Jonathan Bakker <xc-racer2@live.ca>
---
 .../devicetree/bindings/sound/wm8994.txt      | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt
index 367b58ce1bb9..8fa947509c10 100644
--- a/Documentation/devicetree/bindings/sound/wm8994.txt
+++ b/Documentation/devicetree/bindings/sound/wm8994.txt
@@ -68,6 +68,29 @@ Optional properties:
   - wlf,csnaddr-pd : If present enable the internal pull-down resistor on
     the CS/ADDR pin.
 
+Pins on the device (for linking into audio routes):
+
+  * IN1LN
+  * IN1LP
+  * IN2LN
+  * IN2LP:VXRN
+  * IN1RN
+  * IN1RP
+  * IN2RN
+  * IN2RP:VXRP
+  * SPKOUTLP
+  * SPKOUTLN
+  * SPKOUTRP
+  * SPKOUTRN
+  * HPOUT1L
+  * HPOUT1R
+  * HPOUT2P
+  * HPOUT2N
+  * LINEOUT1P
+  * LINEOUT1N
+  * LINEOUT2P
+  * LINEOUT2N
+
 Example:
 
 wm8994: codec@1a {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] dt-bindings: sound: Add bindings for Samsung Aries audio complex
       [not found] <20200614202411.27843-1-xc-racer2@live.ca>
  2020-06-14 20:24 ` [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints Jonathan Bakker
@ 2020-06-14 20:24 ` Jonathan Bakker
  2020-06-14 20:24 ` [PATCH 3/3] ASoC: samsung: Add driver for Aries boards Jonathan Bakker
  2 siblings, 0 replies; 5+ messages in thread
From: Jonathan Bakker @ 2020-06-14 20:24 UTC (permalink / raw)
  To: krzk, sbkim73, s.nawrocki, lgirdwood, broonie, perex, tiwai,
	alsa-devel, linux-kernel, robh+dt, devicetree
  Cc: Jonathan Bakker

The audio system on S5PV210 Aries boards have a wm8994 codec connected
to the Samsung I2S0 DAI.  Jack detection is done via GPIOs, an ADC, and
an extcon device (fsa9480).

There are two main variants, one with an FM radio and where the wm8994 is
the master for the modem audio and the other without FM and the modem is
the master.

Signed-off-by: Jonathan Bakker <xc-racer2@live.ca>
---
 .../bindings/sound/samsung,aries-wm8994.yaml  | 147 ++++++++++++++++++
 1 file changed, 147 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml

diff --git a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml
new file mode 100644
index 000000000000..902a0b66628e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml
@@ -0,0 +1,147 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/samsung,aries-wm8994.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Aries audio complex with WM8994 codec
+
+maintainers:
+  - Jonathan Bakker <xc-racer2@live.ca>
+
+properties:
+  compatible:
+    oneOf:
+      - const: samsung,aries-wm8994
+        description: With FM radio and modem master
+
+      - const: samsung,fascinate4g-wm8994
+        description: Without FM radio and modem slave
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: The user-visible name of this sound complex.
+
+  cpu:
+    type: object
+    properties:
+      sound-dai:
+        minItems: 2
+        maxItems: 2
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+        description: |
+          phandles to the I2S controller and bluetooth codec,
+          in that order
+
+  codec:
+    type: object
+    properties:
+      sound-dai:
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+        description: phandle to the WM8994 CODEC
+
+  samsung,audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description: |
+      List of the connections between audio
+      components;  each entry is a pair of strings, the first being the
+      connection's sink, the second being the connection's source;
+      valid names for sources and sinks are the WM8994's pins (as
+      documented in its binding), and the jacks on the board -
+      For samsung,aries-wm8994: HP, SPK, RCV, LINE, Main Mic, Headset Mic,
+      or FM In
+      For samsung,fascinate4g-wm8994: HP, SPK, RCV, LINE, Main Mic,
+      or HeadsetMic
+
+  extcon:
+    description: Extcon phandle for dock detection
+
+  main-micbias-supply:
+    description: Supply for the micbias on the main mic
+
+  headset-micbias-supply:
+    description: Supply for the micbias on the headset mic
+
+  earpath-sel-gpios:
+    description: GPIO for switching between tv-out and mic paths
+
+  headset-detect-gpios:
+    description: GPIO for detection of headset insertion
+
+  headset-key-gpios:
+    description: GPIO for detection of headset key press
+
+  io-channels:
+    maxItems: 1
+    description: IO channel to read micbias voltage for headset detection
+
+  io-channel-names:
+    const: headset-detect
+
+required:
+  - compatible
+  - model
+  - cpu
+  - codec
+  - samsung,audio-routing
+  - extcon
+  - main-micbias-supply
+  - headset-micbias-supply
+  - earpath-sel-gpios
+  - headset-detect-gpios
+  - headset-key-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    sound {
+        compatible = "samsung,fascinate4g-wm8994";
+
+        model = "Fascinate4G";
+
+        extcon = <&fsa9480>;
+
+        main-micbias-supply = <&main_micbias_reg>;
+        headset-micbias-supply = <&headset_micbias_reg>;
+
+        earpath-sel-gpios = <&gpj2 6 GPIO_ACTIVE_HIGH>;
+
+        io-channels = <&adc 3>;
+        io-channel-names = "headset-detect";
+        headset-detect-gpios = <&gph0 6 GPIO_ACTIVE_HIGH>;
+        headset-key-gpios = <&gph3 6 GPIO_ACTIVE_HIGH>;
+
+        samsung,audio-routing =
+            "HP", "HPOUT1L",
+            "HP", "HPOUT1R",
+
+            "SPK", "SPKOUTLN",
+            "SPK", "SPKOUTLP",
+
+            "RCV", "HPOUT2N",
+            "RCV", "HPOUT2P",
+
+            "LINE", "LINEOUT2N",
+            "LINE", "LINEOUT2P",
+
+            "IN1LP", "Main Mic",
+            "IN1LN", "Main Mic",
+
+            "IN1RP", "Headset Mic",
+            "IN1RN", "Headset Mic";
+
+        pinctrl-names = "default";
+        pinctrl-0 = <&headset_det &earpath_sel>;
+
+        cpu {
+            sound-dai = <&i2s0>, <&bt_codec>;
+        };
+
+        codec {
+            sound-dai = <&wm8994>;
+        };
+    };
+
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] ASoC: samsung: Add driver for Aries boards
       [not found] <20200614202411.27843-1-xc-racer2@live.ca>
  2020-06-14 20:24 ` [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints Jonathan Bakker
  2020-06-14 20:24 ` [PATCH 2/3] dt-bindings: sound: Add bindings for Samsung Aries audio complex Jonathan Bakker
@ 2020-06-14 20:24 ` Jonathan Bakker
  2 siblings, 0 replies; 5+ messages in thread
From: Jonathan Bakker @ 2020-06-14 20:24 UTC (permalink / raw)
  To: krzk, sbkim73, s.nawrocki, lgirdwood, broonie, perex, tiwai,
	alsa-devel, linux-kernel, robh+dt, devicetree
  Cc: Jonathan Bakker

Samsung Aries boards have a WM8994 codec connected to the Samsung
I2S controller, the BT codec, and the cellular modem.  Jack detection
is done by a combination of an ADC, GPIOs, and an extcon device for
the USB dock.  There is also a GPIO for selection between the Mic
path and the TV out path on the headphone jack.

There are two main variants, one with an FM radio and where the modem
is the master and one without a radio and the modem is the slave.

Signed-off-by: Jonathan Bakker <xc-racer2@live.ca>
---
 sound/soc/samsung/Kconfig        |  13 +
 sound/soc/samsung/Makefile       |   2 +
 sound/soc/samsung/aries_wm8994.c | 695 +++++++++++++++++++++++++++++++
 3 files changed, 710 insertions(+)
 create mode 100644 sound/soc/samsung/aries_wm8994.c

diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 112911dc271b..505087d2a50d 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -212,4 +212,17 @@ config SND_SOC_SAMSUNG_TM2_WM5110
 	help
 	  Say Y if you want to add support for SoC audio on the TM2 board.
 
+config SND_SOC_SAMSUNG_ARIES_WM8994
+	tristate "SoC I2S Audio support for WM8994 on Aries"
+	depends on SND_SOC_SAMSUNG && MFD_WM8994 && IIO && EXTCON
+	select SND_SOC_BT_SCO
+	select SND_SOC_WM8994
+	select SND_SAMSUNG_I2S
+	help
+	  Say Y if you want to add support for SoC audio on Aries boards,
+	  which has a WM8994 codec connected to a BT codec, a cellular
+	  modem, and the Samsung I2S controller.  Jack detection is done
+	  via ADC, GPIOs, and an extcon device.  Switching between the Mic
+	  and TV-Out path is also handled.
+
 endif #SND_SOC_SAMSUNG
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 8f5dfe20b9f1..22259f7818f0 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -41,6 +41,7 @@ snd-soc-bells-objs := bells.o
 snd-soc-odroid-objs := odroid.o
 snd-soc-arndale-objs := arndale.o
 snd-soc-tm2-wm5110-objs := tm2_wm5110.o
+snd-soc-aries-wm8994-objs := aries_wm8994.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -64,3 +65,4 @@ obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
 obj-$(CONFIG_SND_SOC_ODROID) += snd-soc-odroid.o
 obj-$(CONFIG_SND_SOC_ARNDALE) += snd-soc-arndale.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_ARIES_WM8994) += snd-soc-aries-wm8994.o
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
new file mode 100644
index 000000000000..8579c87dcae8
--- /dev/null
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/extcon.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/input-event-codes.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "i2s.h"
+#include "../codecs/wm8994.h"
+
+#define ARIES_MCLK1_FREQ 24000000
+
+struct aries_wm8994_variant {
+	unsigned int modem_dai_fmt;
+	bool has_fm_radio;
+};
+
+struct aries_wm8994_data {
+	struct extcon_dev *usb_extcon;
+	struct regulator *reg_main_micbias;
+	struct regulator *reg_headset_micbias;
+	struct gpio_desc *gpio_headset_detect;
+	struct gpio_desc *gpio_headset_key;
+	struct gpio_desc *gpio_earpath_sel;
+	struct iio_channel *adc;
+	const struct aries_wm8994_variant *variant;
+};
+
+/* USB dock */
+static struct snd_soc_jack aries_dock;
+
+static struct snd_soc_jack_pin dock_pins[] = {
+	{
+		.pin = "LINE",
+		.mask = SND_JACK_LINEOUT,
+	},
+};
+
+static int aries_extcon_notifier(struct notifier_block *this,
+				 unsigned long connected, void *_cmd)
+{
+	if (connected)
+		snd_soc_jack_report(&aries_dock, SND_JACK_LINEOUT,
+				SND_JACK_LINEOUT);
+	else
+		snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block aries_extcon_notifier_block = {
+	.notifier_call = aries_extcon_notifier,
+};
+
+/* Headset jack */
+static struct snd_soc_jack aries_headset;
+
+static struct snd_soc_jack_pin jack_pins[] = {
+	{
+		.pin = "HP",
+		.mask = SND_JACK_HEADPHONE,
+	}, {
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static struct snd_soc_jack_zone headset_zones[] = {
+	{
+		.min_mv = 0,
+		.max_mv = 241,
+		.jack_type = SND_JACK_HEADPHONE,
+	}, {
+		.min_mv = 242,
+		.max_mv = 2980,
+		.jack_type = SND_JACK_HEADSET,
+	}, {
+		.min_mv = 2981,
+		.max_mv = UINT_MAX,
+		.jack_type = SND_JACK_HEADPHONE,
+	},
+};
+
+static irqreturn_t headset_det_irq_thread(int irq, void *data)
+{
+	struct aries_wm8994_data *priv = (struct aries_wm8994_data *) data;
+	int ret = 0;
+	int time_left_ms = 300;
+	int adc;
+
+	while (time_left_ms > 0) {
+		if (!gpiod_get_value(priv->gpio_headset_detect)) {
+			snd_soc_jack_report(&aries_headset, 0,
+					SND_JACK_HEADSET);
+			gpiod_set_value(priv->gpio_earpath_sel, 0);
+			return IRQ_HANDLED;
+		}
+		msleep(20);
+		time_left_ms -= 20;
+	}
+
+	/* Temporarily enable micbias and earpath selector */
+	ret = regulator_enable(priv->reg_headset_micbias);
+	if (ret)
+		pr_err("%s failed to enable micbias: %d", __func__, ret);
+
+	gpiod_set_value(priv->gpio_earpath_sel, 1);
+
+	ret = iio_read_channel_processed(priv->adc, &adc);
+	if (ret < 0) {
+		/* failed to read ADC, so assume headphone */
+		pr_err("%s failed to read ADC, assuming headphones", __func__);
+		snd_soc_jack_report(&aries_headset, SND_JACK_HEADPHONE,
+				SND_JACK_HEADSET);
+	} else {
+		snd_soc_jack_report(&aries_headset,
+				snd_soc_jack_get_type(&aries_headset, adc),
+				SND_JACK_HEADSET);
+	}
+
+	ret = regulator_disable(priv->reg_headset_micbias);
+	if (ret)
+		pr_err("%s failed disable micbias: %d", __func__, ret);
+
+	/* Disable earpath selector when no mic connected */
+	if (!(aries_headset.status & SND_JACK_MICROPHONE))
+		gpiod_set_value(priv->gpio_earpath_sel, 0);
+
+	return IRQ_HANDLED;
+}
+
+static int headset_button_check(void *data)
+{
+	struct aries_wm8994_data *priv = (struct aries_wm8994_data *) data;
+
+	/* Filter out keypresses when 4 pole jack not detected */
+	if (gpiod_get_value_cansleep(priv->gpio_headset_key) &&
+			aries_headset.status & SND_JACK_MICROPHONE)
+		return SND_JACK_BTN_0;
+
+	return 0;
+}
+
+static struct snd_soc_jack_gpio headset_button_gpio[] = {
+	{
+		.name = "Media Button",
+		.report = SND_JACK_BTN_0,
+		.debounce_time  = 30,
+		.jack_status_check = headset_button_check,
+	},
+};
+
+static int aries_spk_cfg(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_card *card = w->dapm->card;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_component *component;
+	int ret = 0;
+
+	rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
+	component = asoc_rtd_to_codec(rtd, 0)->component;
+
+	/**
+	 * We have an odd setup - the SPKMODE pin is pulled up so
+	 * we only have access to the left side SPK configs,
+	 * but SPKOUTR isn't bridged so when playing back in
+	 * stereo, we only get the left hand channel.  The only
+	 * option we're left with is to force the AIF into mono
+	 * mode.
+	 */
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		ret = snd_soc_component_update_bits(component,
+				WM8994_AIF1_DAC1_FILTERS_1,
+				WM8994_AIF1DAC1_MONO, WM8994_AIF1DAC1_MONO);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		ret = snd_soc_component_update_bits(component,
+				WM8994_AIF1_DAC1_FILTERS_1,
+				WM8994_AIF1DAC1_MONO, 0);
+		break;
+	}
+
+	return ret;
+}
+
+static int aries_main_bias(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_card *card = w->dapm->card;
+	struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = regulator_enable(priv->reg_main_micbias);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = regulator_disable(priv->reg_main_micbias);
+		break;
+	}
+
+	return ret;
+}
+
+static int aries_headset_bias(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_card *card = w->dapm->card;
+	struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = regulator_enable(priv->reg_headset_micbias);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = regulator_disable(priv->reg_headset_micbias);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new aries_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Modem In"),
+	SOC_DAPM_PIN_SWITCH("Modem Out"),
+};
+
+static const struct snd_soc_dapm_widget aries_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("HP", NULL),
+
+	SND_SOC_DAPM_SPK("SPK", aries_spk_cfg),
+	SND_SOC_DAPM_SPK("RCV", NULL),
+
+	SND_SOC_DAPM_LINE("LINE", NULL),
+
+	SND_SOC_DAPM_MIC("Main Mic", aries_main_bias),
+	SND_SOC_DAPM_MIC("Headset Mic", aries_headset_bias),
+
+	SND_SOC_DAPM_MIC("Bluetooth Mic", NULL),
+	SND_SOC_DAPM_SPK("Bluetooth SPK", NULL),
+
+	SND_SOC_DAPM_LINE("Modem In", NULL),
+	SND_SOC_DAPM_LINE("Modem Out", NULL),
+
+	/* This must be last as it is conditionally not used */
+	SND_SOC_DAPM_LINE("FM In", NULL),
+};
+
+static int aries_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	unsigned int pll_out;
+	int ret;
+
+	/* AIF1CLK should be >=3MHz for optimal performance */
+	if (params_width(params) == 24)
+		pll_out = params_rate(params) * 384;
+	else if (params_rate(params) == 8000 || params_rate(params) == 11025)
+		pll_out = params_rate(params) * 512;
+	else
+		pll_out = params_rate(params) * 256;
+
+	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
+				ARIES_MCLK1_FREQ, pll_out);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+				pll_out, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int aries_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	int ret;
+
+	/* Switch sysclk to MCLK1 */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
+				ARIES_MCLK1_FREQ, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* Stop PLL */
+	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
+				ARIES_MCLK1_FREQ, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * Main DAI operations
+ */
+static struct snd_soc_ops aries_ops = {
+	.hw_params = aries_hw_params,
+	.hw_free = aries_hw_free,
+};
+
+static int aries_baseband_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	unsigned int pll_out;
+	int ret;
+
+	pll_out = 8000 * 512;
+
+	/* Set the codec FLL */
+	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, WM8994_FLL_SRC_MCLK1,
+			ARIES_MCLK1_FREQ, pll_out);
+	if (ret < 0)
+		return ret;
+
+	/* Set the codec system clock */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+			pll_out, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int aries_late_probe(struct snd_soc_card *card)
+{
+	struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
+	int ret, irq;
+
+	ret = snd_soc_card_jack_new(card, "Dock", SND_JACK_LINEOUT,
+			&aries_dock, dock_pins, ARRAY_SIZE(dock_pins));
+	if (ret)
+		return ret;
+
+	ret = devm_extcon_register_notifier(card->dev,
+			priv->usb_extcon, EXTCON_JACK_LINE_OUT,
+			&aries_extcon_notifier_block);
+	if (ret)
+		return ret;
+
+	if (extcon_get_state(priv->usb_extcon,
+			EXTCON_JACK_LINE_OUT) > 0)
+		snd_soc_jack_report(&aries_dock, SND_JACK_LINEOUT,
+				SND_JACK_LINEOUT);
+	else
+		snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT);
+
+	ret = snd_soc_card_jack_new(card, "Headset",
+			SND_JACK_HEADSET | SND_JACK_BTN_0,
+			&aries_headset,
+			jack_pins, ARRAY_SIZE(jack_pins));
+	if (ret)
+		return ret;
+
+	ret = snd_soc_jack_add_zones(&aries_headset, ARRAY_SIZE(headset_zones),
+			headset_zones);
+	if (ret)
+		return ret;
+
+	irq = gpiod_to_irq(priv->gpio_headset_detect);
+	if (irq < 0) {
+		dev_err(card->dev, "Failed to map headset detect gpio to irq");
+		return -EINVAL;
+	}
+
+	ret = devm_request_threaded_irq(card->dev, irq, NULL,
+			headset_det_irq_thread,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			IRQF_ONESHOT, "headset_detect", priv);
+	if (ret) {
+		dev_err(card->dev, "Failed to request headset detect irq");
+		return ret;
+	}
+
+	headset_button_gpio[0].data = priv;
+	headset_button_gpio[0].desc = priv->gpio_headset_key;
+
+	snd_jack_set_key(aries_headset.jack, SND_JACK_BTN_0, KEY_MEDIA);
+
+	return snd_soc_jack_add_gpios(&aries_headset,
+			ARRAY_SIZE(headset_button_gpio), headset_button_gpio);
+}
+
+static const struct snd_soc_pcm_stream baseband_params = {
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rate_min = 8000,
+	.rate_max = 8000,
+	.channels_min = 1,
+	.channels_max = 1,
+};
+
+static const struct snd_soc_pcm_stream bluetooth_params = {
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rate_min = 8000,
+	.rate_max = 8000,
+	.channels_min = 1,
+	.channels_max = 2,
+};
+
+static const struct snd_soc_dapm_widget aries_modem_widgets[] = {
+	SND_SOC_DAPM_INPUT("Modem RX"),
+	SND_SOC_DAPM_OUTPUT("Modem TX"),
+};
+
+static const struct snd_soc_dapm_route aries_modem_routes[] = {
+	{ "Modem Capture", NULL, "Modem RX" },
+	{ "Modem TX", NULL, "Modem Playback" },
+};
+
+static const struct snd_soc_component_driver aries_component = {
+	.name			= "aries-audio",
+	.dapm_widgets		= aries_modem_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aries_modem_widgets),
+	.dapm_routes		= aries_modem_routes,
+	.num_dapm_routes	= ARRAY_SIZE(aries_modem_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver aries_ext_dai[] = {
+	{
+		.name = "Voice call",
+		.playback = {
+			.stream_name = "Modem Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 8000,
+			.rate_max = 8000,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			.stream_name = "Modem Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 8000,
+			.rate_max = 8000,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+};
+
+SND_SOC_DAILINK_DEFS(aif1,
+	DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(baseband,
+	DAILINK_COMP_ARRAY(COMP_CPU("Voice call")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif2")));
+
+SND_SOC_DAILINK_DEFS(bluetooth,
+	DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif3")));
+
+static struct snd_soc_dai_link aries_dai[] = {
+	{
+		.name = "WM8994 AIF1",
+		.stream_name = "HiFi",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
+		.ops = &aries_ops,
+		SND_SOC_DAILINK_REG(aif1),
+	},
+	{
+		.name = "WM8994 AIF2",
+		.stream_name = "Baseband",
+		.init = &aries_baseband_init,
+		.params = &baseband_params,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(baseband),
+	},
+	{
+		.name = "WM8994 AIF3",
+		.stream_name = "Bluetooth",
+		.params = &bluetooth_params,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(bluetooth),
+	},
+};
+
+static struct snd_soc_card aries_card = {
+	.name = "ARIES",
+	.owner = THIS_MODULE,
+	.dai_link = aries_dai,
+	.num_links = ARRAY_SIZE(aries_dai),
+	.controls = aries_controls,
+	.num_controls = ARRAY_SIZE(aries_controls),
+	.dapm_widgets = aries_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(aries_dapm_widgets),
+	.late_probe = aries_late_probe,
+};
+
+static const struct aries_wm8994_variant fascinate4g_variant = {
+	.modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS
+		| SND_SOC_DAIFMT_IB_NF,
+	.has_fm_radio = false,
+};
+
+static const struct aries_wm8994_variant aries_variant = {
+	.modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM
+		| SND_SOC_DAIFMT_IB_NF,
+	.has_fm_radio = true,
+};
+
+static const struct of_device_id samsung_wm8994_of_match[] = {
+	{
+		.compatible = "samsung,fascinate4g-wm8994",
+		.data = &fascinate4g_variant,
+	},
+	{
+		.compatible = "samsung,aries-wm8994",
+		.data = &aries_variant,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
+
+static int aries_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *cpu, *codec, *extcon_np;
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card = &aries_card;
+	struct aries_wm8994_data *priv;
+	struct snd_soc_dai_link *dai_link;
+	const struct of_device_id *match;
+	int ret, i;
+
+	if (!np)
+		return -EINVAL;
+
+	card->dev = dev;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	snd_soc_card_set_drvdata(card, priv);
+
+	match = of_match_node(samsung_wm8994_of_match, np);
+	priv->variant = match->data;
+
+	/* Remove FM widget if not present */
+	if (!priv->variant->has_fm_radio)
+		card->num_dapm_widgets--;
+
+	priv->reg_main_micbias = devm_regulator_get(dev, "main-micbias");
+	if (IS_ERR(priv->reg_main_micbias)) {
+		dev_err(dev, "Failed to get main micbias regulator\n");
+		return PTR_ERR(priv->reg_main_micbias);
+	}
+
+	priv->reg_headset_micbias = devm_regulator_get(dev, "headset-micbias");
+	if (IS_ERR(priv->reg_headset_micbias)) {
+		dev_err(dev, "Failed to get headset micbias regulator\n");
+		return PTR_ERR(priv->reg_headset_micbias);
+	}
+
+	priv->gpio_earpath_sel = devm_gpiod_get(dev, "earpath-sel",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpio_earpath_sel)) {
+		dev_err(dev, "Failed to get earpath selector gpio");
+		return PTR_ERR(priv->gpio_earpath_sel);
+	}
+
+	extcon_np = of_parse_phandle(np, "extcon", 0);
+	priv->usb_extcon = extcon_find_edev_by_node(extcon_np);
+	if (IS_ERR(priv->usb_extcon)) {
+		if (PTR_ERR(priv->usb_extcon) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get extcon device");
+		return PTR_ERR(priv->usb_extcon);
+	}
+	of_node_put(extcon_np);
+
+	priv->adc = devm_iio_channel_get(dev, "headset-detect");
+	if (IS_ERR(priv->adc)) {
+		if (PTR_ERR(priv->adc) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get ADC channel");
+		return PTR_ERR(priv->adc);
+	}
+	if (priv->adc->channel->type != IIO_VOLTAGE)
+		return -EINVAL;
+
+	priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key",
+			GPIOD_IN);
+	if (IS_ERR(priv->gpio_headset_key)) {
+		dev_err(dev, "Failed to get headset key gpio");
+		return PTR_ERR(priv->gpio_headset_key);
+	}
+
+	priv->gpio_headset_detect = devm_gpiod_get(dev,
+			"headset-detect", GPIOD_IN);
+	if (IS_ERR(priv->gpio_headset_detect)) {
+		dev_err(dev, "Failed to get headset detect gpio");
+		return PTR_ERR(priv->gpio_headset_detect);
+	}
+
+	/* Update card-name if provided through DT, else use default name */
+	snd_soc_of_parse_card_name(card, "model");
+
+	ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+	if (ret < 0) {
+		dev_err(dev, "Audio routing invalid/unspecified\n");
+		return ret;
+	}
+
+	aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt;
+
+	cpu = of_get_child_by_name(dev->of_node, "cpu");
+	if (!cpu)
+		return -EINVAL;
+
+	codec = of_get_child_by_name(dev->of_node, "codec");
+	if (!codec)
+		return -EINVAL;
+
+	for_each_card_prelinks(card, i, dai_link) {
+		dai_link->codecs->of_node = of_parse_phandle(codec,
+				"sound-dai", 0);
+		if (!dai_link->codecs->of_node) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	/* Set CPU and platform of_node for main DAI */
+	aries_dai[0].cpus->of_node = of_parse_phandle(cpu,
+			"sound-dai", 0);
+	if (!aries_dai[0].cpus->of_node) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node;
+
+	/* Set CPU of_node for BT DAI */
+	aries_dai[2].cpus->of_node = of_parse_phandle(cpu,
+			"sound-dai", 1);
+	if (!aries_dai[2].cpus->of_node) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = devm_snd_soc_register_component(dev, &aries_component,
+				aries_ext_dai, ARRAY_SIZE(aries_ext_dai));
+	if (ret < 0) {
+		dev_err(dev, "Failed to register component: %d\n", ret);
+		goto out;
+	}
+
+	ret = devm_snd_soc_register_card(dev, card);
+	if (ret)
+		dev_err(dev, "snd_soc_register_card() failed:%d\n", ret);
+
+out:
+	of_node_put(cpu);
+	of_node_put(codec);
+
+	return ret;
+}
+
+static struct platform_driver aries_audio_driver = {
+	.driver		= {
+		.name	= "aries-audio-wm8994",
+		.of_match_table = of_match_ptr(samsung_wm8994_of_match),
+		.pm	= &snd_soc_pm_ops,
+	},
+	.probe		= aries_audio_probe,
+};
+
+module_platform_driver(aries_audio_driver);
+
+MODULE_DESCRIPTION("ALSA SoC ARIES WM8994");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:aries-audio-wm8994");
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints
  2020-06-14 20:24 ` [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints Jonathan Bakker
@ 2020-06-15 12:40   ` Mark Brown
  2020-06-15 23:39   ` Mark Brown
  1 sibling, 0 replies; 5+ messages in thread
From: Mark Brown @ 2020-06-15 12:40 UTC (permalink / raw)
  To: Jonathan Bakker
  Cc: krzk, sbkim73, s.nawrocki, lgirdwood, perex, tiwai, alsa-devel,
	linux-kernel, robh+dt, devicetree

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

On Sun, Jun 14, 2020 at 01:24:09PM -0700, Jonathan Bakker wrote:
> The wm8994 exposes several inputs and outputs that can be used by
> machine drivers in their routing.  Add them to the documention so
> they don't have been duplicated in any machine drivers bindings.

Please submit patches using subject lines reflecting the style for the
subsystem, this makes it easier for people to identify relevant patches.
Look at what existing commits in the area you're changing are doing and
make sure your subject lines visually resemble what they're doing.
There's no need to resubmit to fix this alone.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints
  2020-06-14 20:24 ` [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints Jonathan Bakker
  2020-06-15 12:40   ` Mark Brown
@ 2020-06-15 23:39   ` Mark Brown
  1 sibling, 0 replies; 5+ messages in thread
From: Mark Brown @ 2020-06-15 23:39 UTC (permalink / raw)
  To: robh+dt, s.nawrocki, perex, lgirdwood, alsa-devel, sbkim73,
	Jonathan Bakker, krzk, linux-kernel, tiwai, devicetree

On Sun, 14 Jun 2020 13:24:09 -0700, Jonathan Bakker wrote:
> The wm8994 exposes several inputs and outputs that can be used by
> machine drivers in their routing.  Add them to the documention so
> they don't have been duplicated in any machine drivers bindings.

Applied to

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

Thanks!

[1/3] ASoC: Document wm8994 endpoints
      commit: 3f2ec71cb8f5c9605b5d45918ceefcde9b97b672
[2/3] ASoC: Add bindings for Samsung Aries audio complex
      commit: 14ebd62c12dc89a0087bf86e79548ee9a6d93625
[3/3] ASoC: samsung: Add driver for Aries boards
      commit: 7a3a7671fa6c7e90aff5f4242add2a40587b85ef

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-06-15 23:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20200614202411.27843-1-xc-racer2@live.ca>
2020-06-14 20:24 ` [PATCH 1/3] dt-bindings: sound: Document wm8994 endpoints Jonathan Bakker
2020-06-15 12:40   ` Mark Brown
2020-06-15 23:39   ` Mark Brown
2020-06-14 20:24 ` [PATCH 2/3] dt-bindings: sound: Add bindings for Samsung Aries audio complex Jonathan Bakker
2020-06-14 20:24 ` [PATCH 3/3] ASoC: samsung: Add driver for Aries boards Jonathan Bakker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).