Re: (subset) [PATCH v2 0/7] Initial support for the Fairphone 5 smartphone

2023-09-25 Thread Srinivas Kandagatla


On Tue, 19 Sep 2023 14:45:54 +0200, Luca Weiss wrote:
> Add support to boot up mainline kernel on the QCM6490-based Fairphone 5
> smartphone.
> 
> These patches only cover a part of the functionality brought up on
> mainline so far, with the rest needing larger dts and driver changes or
> depend on patches that are not yet merged. I will work on sending those
> once these base patches here have settled.
> 
> [...]

Applied, thanks!

[2/7] nvmem: qfprom: Mark core clk as optional
  commit: 844ac302b2aa81c47a4323fc34a0a454cc749dbc

Best regards,
-- 
Srinivas Kandagatla 



Re: [PATCH v4 1/9] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-04-15 Thread Srinivas Kandagatla




On 15/04/2021 17:29, Rob Herring wrote:

+codec {
+compatible = "qcom,wcd9380-codec";
+reset-gpios = < 32 0>;
+#sound-dai-cells = <1>;
+qcom,tx-device = <_tx>;
+qcom,rx-device = <_rx>;
+qcom,micbias1-microvolt = <180>;
+qcom,micbias2-microvolt = <180>;
+qcom,micbias3-microvolt = <180>;
+qcom,micbias4-microvolt = <180>;
+qcom,mbhc-hphl-switch;
+qcom,mbhc-ground-switch;
+qcom,mbhc-button0-vthreshold-microvolt = <75000>;
+qcom,mbhc-button1-vthreshold-microvolt = <15>;
+qcom,mbhc-button2-vthreshold-microvolt = <237000>;
+qcom,mbhc-button3-vthreshold-microvolt = <50>;
+qcom,mbhc-button5-vthreshold-microvolt = <50>;
+qcom,mbhc-button6-vthreshold-microvolt = <50>;
+qcom,mbhc-button7-vthreshold-microvolt = <50>;
+};
+
+/* ... */
+
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+wcd938x_tx: codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+qcom,direction = "tx";
+qcom,port-mapping = <2 3 4 5>;
+};
+
+wcd938x_rx: codec@0,4 {
+compatible = "sdw20217010d00";
+reg  = <0 4>;
+qcom,direction = "rx";
+qcom,port-mapping = <1 2 3 4 5>;
+};



This is a single device, right? We shouldn't need 3 nodes to describe


Just realized that the example is bit misleading here.
It should look like:

 codec {
compatible = "qcom,wcd9380-codec";
reset-gpios = < 32 0>;
#sound-dai-cells = <1>;
qcom,tx-device = <_tx>;
qcom,rx-device = <_rx>;
qcom,micbias1-microvolt = <180>;
qcom,micbias2-microvolt = <180>;
qcom,micbias3-microvolt = <180>;
qcom,micbias4-microvolt = <180>;
qcom,mbhc-hphl-switch;
qcom,mbhc-ground-switch;
qcom,mbhc-button0-vthreshold-microvolt = <75000>;
qcom,mbhc-button1-vthreshold-microvolt = <15>;
qcom,mbhc-button2-vthreshold-microvolt = <237000>;
qcom,mbhc-button3-vthreshold-microvolt = <50>;
qcom,mbhc-button5-vthreshold-microvolt = <50>;
qcom,mbhc-button6-vthreshold-microvolt = <50>;
qcom,mbhc-button7-vthreshold-microvolt = <50>;
};


soundwire-controller@323 {
reg = <0 0x323 0 0x2000>;
compatible = "qcom,soundwire-v1.5.1";
wcd938x_tx: codec@0,3 {
compatible = "sdw20217010d00";
reg  = <0 3>;
qcom,direction = "tx";
qcom,port-mapping = <2 3 4 5>;
};
};


soundwire-controller@321 {
reg = <0 0x321 0 0x2000>;
compatible = "qcom,soundwire-v1.5.1";
 wcd938x_rx: codec@0,4 {
compatible = "sdw20217010d00";
reg  = <0 4>;
qcom,direction = "rx";
qcom,port-mapping = <1 2 3 4 5>;
};
};


--srini


Re: [PATCH v4 4/9] ASoC: dt-bindings: wcd938x-sdw: add bindings for wcd938x-sdw

2021-04-15 Thread Srinivas Kandagatla




On 15/04/2021 17:39, Rob Herring wrote:

On Wed, Apr 14, 2021 at 04:48:40PM +0100, Srinivas Kandagatla wrote:

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices RX and
TX respectively. This bindings is for those slave devices on WCD9380/WCD9385.

Signed-off-by: Srinivas Kandagatla 
---
  .../bindings/sound/qcom,wcd938x-sdw.yaml  | 61 +++
  1 file changed, 61 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
new file mode 100644
index ..fff33c65491b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd938x-sdw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm SoundWire Slave devices on WCD9380/WCD9385
+
+maintainers:
+  - Srinivas Kandagatla 
+
+description: |
+  Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices. This bindings is for the
+  slave devices.
+
+properties:
+  compatible:
+const: sdw20217010d00
+
+  reg:
+maxItems: 1
+
+  qcom,direction:
+description: direction of the SoundWire device instance
+enum:
+  - rx
+  - tx


Was thinking these were some established bus properties...

This would just be implied by the 'reg' property index. You could define
'reg-names' too I guess.


+
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+$ref: /schemas/types.yaml#/definitions/uint32-array
+minItems: 4
+maxItems: 5


qcom,rx-port-mapping and qcom,tx-port-mapping?



If we have this property then "qcom,direction" becomes redundant.


Or keep a single property and the driver knows how many slave ports for
each direction. IOW, an array of 9 with first 4 entries for tx and last
5 for rx.


We can't have a single property with 9 entries as these are two separate 
devices, rx SoundWire Slave has 5 ports implemented where as tx SounWire 
slave has only 4 ports implemented in hw.


And the are on different SoundWire buses.

--srini



+
+required:
+  - compatible
+  - reg
+  - qcom,direction
+  - qcom,port-mapping
+
+additionalProperties: false
+
+examples:
+  - |
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+
+codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+qcom,direction = "tx";
+qcom,port-mapping = <2 3 4 5>;
+};
+};
+
+...
--
2.21.0



Re: [PATCH v4 1/9] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-04-15 Thread Srinivas Kandagatla

Thanks Rob for quick review,

On 15/04/2021 17:29, Rob Herring wrote:

On Wed, Apr 14, 2021 at 04:48:37PM +0100, Srinivas Kandagatla wrote:

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire device RX and
TX respectively, supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs, MBHC.

Signed-off-by: Srinivas Kandagatla 
---
  .../bindings/sound/qcom,wcd938x.yaml  | 176 ++
  1 file changed, 176 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
new file mode 100644
index ..4c8fa8290af0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
@@ -0,0 +1,176 @@


...


+additionalProperties: false
+
+examples:
+  - |
+codec {
+compatible = "qcom,wcd9380-codec";
+reset-gpios = < 32 0>;
+#sound-dai-cells = <1>;
+qcom,tx-device = <_tx>;
+qcom,rx-device = <_rx>;
+qcom,micbias1-microvolt = <180>;
+qcom,micbias2-microvolt = <180>;
+qcom,micbias3-microvolt = <180>;
+qcom,micbias4-microvolt = <180>;
+qcom,mbhc-hphl-switch;
+qcom,mbhc-ground-switch;
+qcom,mbhc-button0-vthreshold-microvolt = <75000>;
+qcom,mbhc-button1-vthreshold-microvolt = <15>;
+qcom,mbhc-button2-vthreshold-microvolt = <237000>;
+qcom,mbhc-button3-vthreshold-microvolt = <50>;
+qcom,mbhc-button5-vthreshold-microvolt = <50>;
+qcom,mbhc-button6-vthreshold-microvolt = <50>;
+qcom,mbhc-button7-vthreshold-microvolt = <50>;
+};
+
+/* ... */
+
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+wcd938x_tx: codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+qcom,direction = "tx";
+qcom,port-mapping = <2 3 4 5>;
+};
+
+wcd938x_rx: codec@0,4 {
+compatible = "sdw20217010d00";
+reg  = <0 4>;
+qcom,direction = "rx";
+qcom,port-mapping = <1 2 3 4 5>;
+};


This is a single device, right? We shouldn't need 3 nodes to describe
it. I think this should all be a single node like this:

No, WCD938x is a Audio Codec which has two SoundWire Slave device (TX 
and RX). WCD938X reset lines and supplies are common for both TX and RX 
SoundWire devices.


However TX SoundWire device only has register access to codec 
CSR(Control Status registers).


So there are two SoundWire devices and a WCD938X common parts. Now 
making the common Codec part as a separate device made more sense here.

So we ended with total 3 devices.

1 . WCD938x Codec which deals with all the codec side including Common 
parts.
2. TX SoundWire device to configure TX SoundWire ports/interface and 
provide CSR access.

3. RX SoundWire device to configure RX Soundwire ports/interface



codec@0,3 {
 reg = <0 3>, <0 4>;


We can't have this, as these two SoundWire devices hang on different 
SoundWire bus instances.



compatible = "sdw20217010d00";

 reset-gpios = < 32 0>;
 #sound-dai-cells = <1>;
 qcom,micbias1-microvolt = <180>;
 qcom,micbias2-microvolt = <180>;
 qcom,micbias3-microvolt = <180>;
 qcom,micbias4-microvolt = <180>;
 qcom,mbhc-hphl-switch;
 qcom,mbhc-ground-switch;
 qcom,mbhc-button0-vthreshold-microvolt = <75000>;
 qcom,mbhc-button1-vthreshold-microvolt = <15>;
 qcom,mbhc-button2-vthreshold-microvolt = <237000>;
 qcom,mbhc-button3-vthreshold-microvolt = <50>;
 qcom,mbhc-button5-vthreshold-microvolt = <50>;
 qcom,mbhc-button6-vthreshold-microvolt = <50>;
 qcom,mbhc-button7-vthreshold-microvolt = <50>;
};

You'll have to figure out the qcom,direction and qcom,port-mapping parts
though.


That is the reason why we ended up with 3 devices here.

--srini


Rob



Re: [PATCH] ASoC: codecs: wcd934x: Fix missing IRQF_ONESHOT as only threaded handler

2021-04-15 Thread Srinivas Kandagatla




On 15/04/2021 08:38, zhuguangqin...@gmail.com wrote:

From: Guangqing Zhu 

Coccinelle noticed:
   sound/soc/codecs/wcd934x.c:5041:7-32: ERROR: Threaded IRQ with no primary
handler requested without IRQF_ONESHOT

Signed-off-by: Guangqing Zhu 
---


Thanks for the patch,

Reviewed-by: Srinivas Kandagatla 


  sound/soc/codecs/wcd934x.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index 5fe403307b72..cddc49bbb7f6 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -5040,7 +5040,7 @@ static int wcd934x_codec_probe(struct platform_device 
*pdev)
  
  	ret = devm_request_threaded_irq(dev, irq, NULL,

wcd934x_slim_irq_handler,
-   IRQF_TRIGGER_RISING,
+   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"slim", wcd);
if (ret) {
dev_err(dev, "Failed to request slimbus irq\n");



[PATCH v4 7/9] ASoC: codecs: wcd938x: add playback dapm widgets

2021-04-14 Thread Srinivas Kandagatla
This patch adds required dapm widgets for playback.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 687 +
 1 file changed, 687 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index ae503d1d6379..bfd8d8ea6f04 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1328,6 +1328,593 @@ static int wcd938x_connect_port(struct wcd938x_sdw_priv 
*wcd, u8 ch_id, u8 enabl
enable);
 }
 
+static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX0_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX1_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX2_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, WCD938X_AUX_AUXPA,
+ WCD938X_AUXPA_CLK_EN_MASK, 1);
+   break;
+   case SND_SOC_DAPM_POST_PMD:
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VNEG_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VPOS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 0);
+   break;
+   }
+   return 0;
+}
+
+static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+   struct snd_kcontrol *kcontrol,
+   int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_DIG_CLK_CTL,
+   WCD938X_RXD0_CLK_EN_MASK, 0x01);
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_HPH_GAIN_CTL,
+   WCD938X_HPHL_RX_EN_MASK, 1);
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_RDAC_CLK_CTL1,
+   WCD938X_CHOP_CLK_EN_MASK, 0);
+   break;
+   case SND_SOC_DAPM_POST_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+   WCD938X_HPH_RES_DIV_MASK, 0x02);
+   if (wcd938x->comp1_enable) {
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_COMP_CTL_0,
+   WCD938X_HPHL_COMP_EN_MASK, 1);
+   /* 5msec compander delay as per HW requirement */
+   if (!wcd938x->comp2_enable || 
(snd_soc_component_read(component,
+
WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01))
+   usleep_range(5000, 5010);
+   snd_soc_component_write_field(component, 
WCD938X_HPH_NEW_INT_HPH_TIMER1,
+ WCD938X_AUTOCHOP_TIMER_EN, 0);
+   } else {
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_COMP_CTL_0,
+   WCD938X_HPHL

[PATCH v4 8/9] ASoC: codecs: wcd938x: add capture dapm widgets

2021-04-14 Thread Srinivas Kandagatla
This patch adds required dapm widgets for capture path.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 785 +
 1 file changed, 785 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index bfd8d8ea6f04..05e1b0fc4f5f 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -158,6 +158,16 @@ enum {
NUM_CODEC_DAIS,
 };
 
+static u8 tx_mode_bit[] = {
+   [ADC_MODE_INVALID] = 0x00,
+   [ADC_MODE_HIFI] = 0x01,
+   [ADC_MODE_LO_HIF] = 0x02,
+   [ADC_MODE_NORMAL] = 0x04,
+   [ADC_MODE_LP] = 0x08,
+   [ADC_MODE_ULP1] = 0x10,
+   [ADC_MODE_ULP2] = 0x20,
+};
+
 struct wcd938x_priv {
struct sdw_slave *tx_sdw_dev;
struct wcd938x_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
@@ -1240,6 +1250,70 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = {
.irq_drv_data = NULL,
 };
 
+static int wcd938x_swr_slv_get_current_bank(struct wcd938x_sdw_priv *wcd)
+{
+   int bank;
+
+   bank  = sdw_read(wcd->sdev, SDW_SCP_CTRL);
+
+   return ((bank & 0x40) ? 1 : 0);
+}
+
+static int wcd938x_get_clk_rate(int mode)
+{
+   int rate;
+
+   switch (mode) {
+   case ADC_MODE_ULP2:
+   rate = SWR_CLK_RATE_0P6MHZ;
+   break;
+   case ADC_MODE_ULP1:
+   rate = SWR_CLK_RATE_1P2MHZ;
+   break;
+   case ADC_MODE_LP:
+   rate = SWR_CLK_RATE_4P8MHZ;
+   break;
+   case ADC_MODE_NORMAL:
+   case ADC_MODE_LO_HIF:
+   case ADC_MODE_HIFI:
+   case ADC_MODE_INVALID:
+   default:
+   rate = SWR_CLK_RATE_9P6MHZ;
+   break;
+   }
+
+   return rate;
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int 
rate, int bank)
+{
+   u8 mask = (bank ? 0xF0 : 0x0F);
+   u8 val = 0;
+
+   switch (rate) {
+   case SWR_CLK_RATE_0P6MHZ:
+   val = (bank ? 0x60 : 0x06);
+   break;
+   case SWR_CLK_RATE_1P2MHZ:
+   val = (bank ? 0x50 : 0x05);
+   break;
+   case SWR_CLK_RATE_2P4MHZ:
+   val = (bank ? 0x30 : 0x03);
+   break;
+   case SWR_CLK_RATE_4P8MHZ:
+   val = (bank ? 0x10 : 0x01);
+   break;
+   case SWR_CLK_RATE_9P6MHZ:
+   default:
+   val = 0x00;
+   break;
+   }
+   snd_soc_component_update_bits(component, 
WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+ mask, val);
+
+   return 0;
+}
+
 static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
 {
struct regmap *rm = wcd938x->regmap;
@@ -1915,6 +1989,455 @@ static int wcd938x_codec_enable_ear_pa(struct 
snd_soc_dapm_widget *w,
return 0;
 }
 
+static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol,
+int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   u16 dmic_clk_reg, dmic_clk_en_reg;
+   u8 dmic_sel_mask, dmic_clk_mask;
+
+   switch (w->shift) {
+   case 0:
+   case 1:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL;
+   dmic_clk_mask = WCD938X_DMIC1_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK;
+   break;
+   case 2:
+   case 3:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL;
+   dmic_clk_mask = WCD938X_DMIC2_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK;
+   break;
+   case 4:
+   case 5:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL;
+   dmic_clk_mask = WCD938X_DMIC3_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK;
+   break;
+   case 6:
+   case 7:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL;
+   dmic_clk_mask = WCD938X_DMIC4_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK;
+   break;
+   default:
+   dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+   __func__);
+   return -EINVAL;
+   };
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_AMIC_CTL,
+   dmic_sel_mask,
+   WCD938X_AMIC1_IN_SEL_DMIC);
+   /* 250us sleep as per HW requirement */
+   

[PATCH v4 6/9] ASoC: codecs: wcd938x: add basic controls

2021-04-14 Thread Srinivas Kandagatla
This patch adds basic controls found in wcd938x codec.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 409 +
 1 file changed, 409 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 0803b5e72326..ae503d1d6379 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -75,6 +75,15 @@
 #define WCD938X_MBHC_MOISTURE_RREF  R_24_KOHM
 #define WCD_MBHC_HS_V_MAX   1600
 
+#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
+{  .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+   .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+   .tlv.p = (tlv_array), \
+   .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+   .put = wcd938x_ear_pa_put_gain, \
+   .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+
 enum {
WCD9380 = 0,
WCD9385 = 5,
@@ -198,6 +207,10 @@ enum {
MICB_DISABLE,
 };
 
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
+
 static const struct reg_default wcd938x_defaults[] = {
{WCD938X_ANA_PAGE_REGISTER,0x00},
{WCD938X_ANA_BIAS, 0x00},
@@ -1282,6 +1295,375 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
 
 }
 
+static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+   struct sdw_port_config *port_config,
+   u32 mstr_port_num,
+   u8 enable)
+{
+   u8 ch_mask, port_num;
+
+   port_num = ch_info->port_num;
+   ch_mask = ch_info->ch_mask;
+
+   port_config->num = port_num;
+
+   if (enable)
+   port_config->ch_mask |= ch_mask;
+   else
+   port_config->ch_mask &= ~ch_mask;
+
+   return 0;
+}
+
+static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 
enable)
+{
+   u8 port_num, mstr_port_num;
+
+   port_num = wcd->ch_info[ch_id].port_num;
+   mstr_port_num = wcd->port_map[port_num - 1];
+
+   return wcd938x_sdw_connect_port(>ch_info[ch_id],
+   >port_config[port_num],
+   mstr_port_num,
+   enable);
+}
+
+static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   ucontrol->value.integer.value[0] = wcd938x->tx_mode[path];
+
+   return 0;
+}
+
+static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+   ucontrol->value.integer.value[0] = wcd938x->hph_mode;
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+   wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+   if (wcd938x->comp1_enable) {
+   dev_err(component->dev, "Can not set EAR PA Gain, compander1 is 
enabled\n");
+   return -EINVAL;
+   }
+
+   snd_soc_component_write_field(component, WCD938X

[PATCH v4 9/9] ASoC: codecs: wcd938x: add audio routing

2021-04-14 Thread Srinivas Kandagatla
This patch adds audio routing for both playback and capture.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 94 ++
 1 file changed, 94 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 05e1b0fc4f5f..e0be916bad65 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -3132,6 +3132,98 @@ static const struct snd_soc_dapm_widget 
wcd938x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("AUX"),
SND_SOC_DAPM_OUTPUT("HPHL"),
SND_SOC_DAPM_OUTPUT("HPHR"),
+
+};
+
+static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
+   {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+   {"ADC1_MIXER", "Switch", "ADC1 REQ"},
+   {"ADC1 REQ", NULL, "ADC1"},
+   {"ADC1", NULL, "AMIC1"},
+
+   {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+   {"ADC2_MIXER", "Switch", "ADC2 REQ"},
+   {"ADC2 REQ", NULL, "ADC2"},
+   {"ADC2", NULL, "HDR12 MUX"},
+   {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"},
+   {"HDR12 MUX", "HDR12", "AMIC1"},
+   {"ADC2 MUX", "INP3", "AMIC3"},
+   {"ADC2 MUX", "INP2", "AMIC2"},
+
+   {"ADC3_OUTPUT", NULL, "ADC3_MIXER"},
+   {"ADC3_MIXER", "Switch", "ADC3 REQ"},
+   {"ADC3 REQ", NULL, "ADC3"},
+   {"ADC3", NULL, "HDR34 MUX"},
+   {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"},
+   {"HDR34 MUX", "HDR34", "AMIC5"},
+   {"ADC3 MUX", "INP4", "AMIC4"},
+   {"ADC3 MUX", "INP6", "AMIC6"},
+
+   {"ADC4_OUTPUT", NULL, "ADC4_MIXER"},
+   {"ADC4_MIXER", "Switch", "ADC4 REQ"},
+   {"ADC4 REQ", NULL, "ADC4"},
+   {"ADC4", NULL, "ADC4 MUX"},
+   {"ADC4 MUX", "INP5", "AMIC5"},
+   {"ADC4 MUX", "INP7", "AMIC7"},
+
+   {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+   {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+   {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+   {"DMIC2_MIXER", "Switch", "DMIC2"},
+
+   {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"},
+   {"DMIC3_MIXER", "Switch", "DMIC3"},
+
+   {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"},
+   {"DMIC4_MIXER", "Switch", "DMIC4"},
+
+   {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"},
+   {"DMIC5_MIXER", "Switch", "DMIC5"},
+
+   {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"},
+   {"DMIC6_MIXER", "Switch", "DMIC6"},
+
+   {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"},
+   {"DMIC7_MIXER", "Switch", "DMIC7"},
+
+   {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"},
+   {"DMIC8_MIXER", "Switch", "DMIC8"},
+
+   {"IN1_HPHL", NULL, "VDD_BUCK"},
+   {"IN1_HPHL", NULL, "CLS_H_PORT"},
+
+   {"RX1", NULL, "IN1_HPHL"},
+   {"RX1", NULL, "RXCLK"},
+   {"RDAC1", NULL, "RX1"},
+   {"HPHL_RDAC", "Switch", "RDAC1"},
+   {"HPHL PGA", NULL, "HPHL_RDAC"},
+   {"HPHL", NULL, "HPHL PGA"},
+
+   {"IN2_HPHR", NULL, "VDD_BUCK"},
+   {"IN2_HPHR", NULL, "CLS_H_PORT"},
+   {"RX2", NULL, "IN2_HPHR"},
+   {"RDAC2", NULL, "RX2"},
+   {"RX2", NULL, "RXCLK"},
+   {"HPHR_RDAC", "Switch", "RDAC2"},
+   {"HPHR PGA", NULL, "HPHR_RDAC"},
+   {"HPHR", NULL, "HPHR PGA"},
+
+   {"IN3_AUX", NULL, "VDD_BUCK"},
+   {"IN3_AUX", NULL, "CLS_H_PORT"},
+   {"RX3", NULL, "IN3_AUX"},
+   {"RDAC4", NULL, "RX3"},
+   {"RX3", NULL, "RXCLK"},
+   {"AUX_RDAC", "Switch", "RDAC4"},
+   {"AUX PGA", NULL, "AUX_RDAC"},
+   {"AUX", NULL, "AUX PGA"},
+
+   {"RDAC3_MUX", "RX3", "RX3"},
+   {"RDAC3_MUX", "RX1", "RX1"},
+   {"RDAC3", NULL, "RDAC3_MUX"},
+   {"EAR_RDAC", "Switch", "RDAC3"},
+   {"EAR PGA", NULL, "EAR_RDAC"},
+   {"EAR", NULL, "EAR PGA"},
 };
 
 static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
@@ -3299,6 +3391,8 @@ static const struct snd_soc_component_driver 
soc_codec_dev_wcd938x = {
.num_controls = ARRAY_SIZE(wcd938x_snd_controls),
.dapm_widgets = wcd938x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets),
+   .dapm_routes = wcd938x_audio_map,
+   .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map),
 };
 
 static void wcd938x_dt_parse_micbias_info(struct device *dev, struct 
wcd938x_priv *wcd)
-- 
2.21.0



[PATCH v4 4/9] ASoC: dt-bindings: wcd938x-sdw: add bindings for wcd938x-sdw

2021-04-14 Thread Srinivas Kandagatla
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices RX and
TX respectively. This bindings is for those slave devices on WCD9380/WCD9385.

Signed-off-by: Srinivas Kandagatla 
---
 .../bindings/sound/qcom,wcd938x-sdw.yaml  | 61 +++
 1 file changed, 61 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
new file mode 100644
index ..fff33c65491b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd938x-sdw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm SoundWire Slave devices on WCD9380/WCD9385
+
+maintainers:
+  - Srinivas Kandagatla 
+
+description: |
+  Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices. This bindings is for the
+  slave devices.
+
+properties:
+  compatible:
+const: sdw20217010d00
+
+  reg:
+maxItems: 1
+
+  qcom,direction:
+description: direction of the SoundWire device instance
+enum:
+  - rx
+  - tx
+
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+$ref: /schemas/types.yaml#/definitions/uint32-array
+minItems: 4
+maxItems: 5
+
+required:
+  - compatible
+  - reg
+  - qcom,direction
+  - qcom,port-mapping
+
+additionalProperties: false
+
+examples:
+  - |
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+
+codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+qcom,direction = "tx";
+qcom,port-mapping = <2 3 4 5>;
+};
+};
+
+...
-- 
2.21.0



[PATCH v4 5/9] ASoC: codecs: wcd938x-sdw: add SoundWire driver

2021-04-14 Thread Srinivas Kandagatla
This patch adds support to SoundWire devices on WCD9380/WCD9385 Codec

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/Kconfig   |   9 ++
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/wcd938x-sdw.c | 230 +
 3 files changed, 241 insertions(+)
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e81950c735ce..ca640d7a6064 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1537,6 +1537,15 @@ config SND_SOC_WCD934X
 config SND_SOC_WCD938X
tristate
 
+config SND_SOC_WCD938X_SDW
+   tristate "WCD9380/WCD9385 Codec - SDW
+   select SND_SOC_WCD938X
+   depends on SOUNDWIRE
+   select REGMAP_SOUNDWIRE
+   help
+ The WCD9380/9385 is a audio codec IC Integrated in
+ Qualcomm SoCs like SM8250.
+
 config SND_SOC_WL1273
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index e4334626c2d6..2440846f8811 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -253,6 +253,7 @@ snd-soc-uda1380-objs := uda1380.o
 snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
 snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
 snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o
+snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -576,6 +577,7 @@ obj-$(CONFIG_SND_SOC_UDA1380)   += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WCD9335)  += snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)  += snd-soc-wcd934x.o
 obj-$(CONFIG_SND_SOC_WCD938X)  += snd-soc-wcd938x.o
+obj-$(CONFIG_SND_SOC_WCD938X_SDW) += snd-soc-wcd938x-sdw.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM0010)   += snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
new file mode 100644
index ..73a22e889d37
--- /dev/null
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021, Linaro Limited
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "wcd938x.h"
+
+#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
+};
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)),
+   WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC7, WCD938X_DMIC_4_7_PORT, BIT(3)),
+};
+
+static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = {
+   {
+   .num = 1,
+   .type = SDW_DPN_SIMPLE,
+   .min_ch = 1,
+   .max_ch = 8,
+   .simple_ch_prep_sm = true,
+   }, {
+   .num = 2,
+   .type = SDW_DPN_SIMPLE,
+   .min_ch = 1,
+   .max_ch = 4,
+   .simple_ch_prep_sm = true,
+   }, {
+   .num = 3,
+   .type = SDW_DPN_SIMPLE,
+   .min_ch = 1,
+   .max_ch = 4,
+   .simple_ch_prep_sm = true,
+   }, {
+   .num = 4,
+   .type = SDW_DPN_SIMPLE,
+   .min_ch = 1,
+   .max_ch = 4,
+   .simple_ch_prep_sm = true,
+   }, {
+   .num = 5,
+   .type = SDW_DPN_SIMPLE,
+   .min_ch = 1,
+   .max_ch = 4,
+   .simple_ch_prep_sm = true,
+   }
+};
+
+static int wcd9380_update_status(struct s

[PATCH v4 2/9] ASoC: codecs: wcd-clsh: add new version support

2021-04-14 Thread Srinivas Kandagatla
>From WCD937X Class H controller has changed significantly, so add support
to this new version for WCD937X and WCD938X Codecs.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd-clsh-v2.c | 348 -
 sound/soc/codecs/wcd-clsh-v2.h |  16 ++
 2 files changed, 354 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 817d8259758c..485d1932391a 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -88,6 +88,19 @@ struct wcd_clsh_ctrl {
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
 
+#define WCD9XXX_BASE_ADDRESS   0x3000
+#define WCD9XXX_ANA_RX_SUPPLIES
(WCD9XXX_BASE_ADDRESS+0x008)
+#define WCD9XXX_ANA_HPH
(WCD9XXX_BASE_ADDRESS+0x009)
+#define WCD9XXX_CLASSH_MODE_2  
(WCD9XXX_BASE_ADDRESS+0x098)
+#define WCD9XXX_CLASSH_MODE_3  
(WCD9XXX_BASE_ADDRESS+0x099)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_1
(WCD9XXX_BASE_ADDRESS+0x0A5)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_4
(WCD9XXX_BASE_ADDRESS+0x0A8)
+#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 
(WCD9XXX_BASE_ADDRESS+0x0AF)
+#define WCD9XXX_RX_BIAS_HPH_LOWPOWER   
(WCD9XXX_BASE_ADDRESS+0x0BF)
+#define WCD9XXX_V3_RX_BIAS_FLYB_BUFF   
(WCD9XXX_BASE_ADDRESS+0x0C7)
+#define WCD9XXX_HPH_PA_CTL1
(WCD9XXX_BASE_ADDRESS+0x0D1)
+#define WCD9XXX_HPH_NEW_INT_PA_MISC2   
(WCD9XXX_BASE_ADDRESS+0x138)
+
 #define CLSH_REQ_ENABLEtrue
 #define CLSH_REQ_DISABLE   false
 #define WCD_USLEEP_RANGE   50
@@ -137,6 +150,20 @@ static inline void wcd_clsh_set_buck_mode(struct 
snd_soc_component *comp,
WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
 }
 
+static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component,
+ int mode)
+{
+   if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+   mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x08); /* set to HIFI */
+   else
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x00); /* set to default */
+}
+
 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
 int mode)
 {
@@ -170,6 +197,36 @@ static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
usleep_range(500, 500 + WCD_USLEEP_RANGE);
 }
 
+static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component,
+  struct wcd_clsh_ctrl *ctrl,
+  int mode,
+  bool enable)
+{
+   /* enable/disable buck */
+   if ((enable && (++ctrl->buck_users == 1)) ||
+  (!enable && (--ctrl->buck_users == 0))) {
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   (1 << 7), (enable << 7));
+   /*
+* 500us sleep is required after buck enable/disable
+* as per HW requirement
+*/
+   usleep_range(500, 510);
+   if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
+   mode == CLS_H_HIFI || mode == CLS_H_LP)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_3,
+   0x02, 0x00);
+
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_2,
+   0xFF, 0x3A);
+   /* 500usec delay is needed as per HW requirement */
+   usleep_range(500, 500 + WCD_USLEEP_RANGE);
+   }
+}
+
 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
  int mode,
  bool enable)
@@ -219,8 +276,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl 
*ctrl, int mode)
val);
 }
 
-static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp,
- int mode)
+static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode)
 {
int val = 0, gain = 0, res_val;
int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
@@ -264,6 +320,48 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component 
*comp,
   

[PATCH v4 3/9] ASoC: codecs: wcd938x: add basic driver

2021-04-14 Thread Srinivas Kandagatla
This patch adds basic SoundWire codec driver to support for
WCD938X TX and RX devices.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/wcd938x.c | 1811 
 sound/soc/codecs/wcd938x.h |  670 +
 4 files changed, 2487 insertions(+)
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 2a7b3e363069..e81950c735ce 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -232,6 +232,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
+   imply SND_SOC_WCD938X
imply SND_SOC_LPASS_RX_MACRO
imply SND_SOC_LPASS_TX_MACRO
imply SND_SOC_WL1273
@@ -1533,6 +1534,9 @@ config SND_SOC_WCD934X
  The WCD9340/9341 is a audio codec IC Integrated in
  Qualcomm SoCs like SDM845.
 
+config SND_SOC_WCD938X
+   tristate
+
 config SND_SOC_WL1273
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0efdba609048..e4334626c2d6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -252,6 +252,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
 snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
+snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -574,6 +575,7 @@ obj-$(CONFIG_SND_SOC_UDA134X)   += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WCD9335)  += snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)  += snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD938X)  += snd-soc-wcd938x.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM0010)   += snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
new file mode 100644
index ..0803b5e72326
--- /dev/null
+++ b/sound/soc/codecs/wcd938x.c
@@ -0,0 +1,1811 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "wcd-clsh-v2.h"
+#include "wcd938x.h"
+
+#define WCD938X_MAX_MICBIAS(4)
+#define WCD938X_MAX_SUPPLY (4)
+#define WCD938X_MBHC_MAX_BUTTONS   (8)
+#define TX_ADC_MAX (4)
+#define WCD938X_TX_MAX_SWR_PORTS   (5)
+
+#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+   SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+   SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+SNDRV_PCM_RATE_176400)
+#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+   SNDRV_PCM_FMTBIT_S24_LE)
+/* Convert from vout ctl to micbias voltage in mV */
+#define  WCD_VOUT_CTL_TO_MICB(v)   (1000 + v * 50)
+#define SWR_CLK_RATE_0P6MHZ(60)
+#define SWR_CLK_RATE_1P2MHZ(120)
+#define SWR_CLK_RATE_2P4MHZ(240)
+#define SWR_CLK_RATE_4P8MHZ(480)
+#define SWR_CLK_RATE_9P6MHZ(960)
+#define SWR_CLK_RATE_11P2896MHZ(1128960)
+
+#define WCD938X_DRV_NAME "wcd938x_codec"
+#define WCD938X_VERSION_1_0(1)
+#define EAR_RX_PATH_AUX(1)
+
+#define ADC_MODE_VAL_HIFI  0x01
+#define ADC_MODE_VAL_LO_HIF0x02
+#define ADC_MODE_VAL_NORMAL0x03
+#define ADC_MODE_VAL_LP0x05
+#define ADC_MODE_VAL_ULP1  0x09
+#define ADC_MODE_VAL_ULP2  0x0B
+
+/* Z value defined in milliohm */
+#define WCD938X_ZDET_VAL_32 (32000)
+#define WCD938X_ZDET_VAL_400(40)
+#define WCD938X_ZDET_VAL_1200   (120)
+#define WCD938X_ZDET_VAL_100K   (1)
+/* Z floating defined in ohms */
+#define WCD938X_ZDET_FLOATING_IMPEDANCE(0x0FFE)
+#define WCD938X_ZDET_NUM_MEASUREMENTS   (900)
+#define WCD938X_MBHC_GET_C1(c)  ((c & 0xC000) >> 14)
+#define WCD938X_MBHC_GET_X1(x)  (x & 0x3FFF)
+/* Z value compared in milliOhm */
+#define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 40) || (z < 32000))
+#define WCD938X_MBHC_ZDET_CONST (86 * 16384)
+#define WCD938X_MBHC_MOISTURE_RREF  R_24_KOHM

[PATCH v4 1/9] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-04-14 Thread Srinivas Kandagatla
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire device RX and
TX respectively, supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs, MBHC.

Signed-off-by: Srinivas Kandagatla 
---
 .../bindings/sound/qcom,wcd938x.yaml  | 176 ++
 1 file changed, 176 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
new file mode 100644
index ..4c8fa8290af0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd938x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm WCD9380/WCD9385 Audio Codec
+
+maintainers:
+  - Srinivas Kandagatla 
+
+description: |
+  Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices.
+
+properties:
+  compatible:
+enum:
+  - qcom,wcd9380-codec
+  - qcom,wcd9385-codec
+
+  reset-gpios:
+description: GPIO spec for reset line to use
+maxItems: 1
+
+  vdd-buck-supply:
+description: A reference to the 1.8V buck supply
+
+  vdd-rxtx-supply:
+description: A reference to the 1.8V rx supply
+
+  vdd-io-supply:
+description: A reference to the 1.8V I/O supply
+
+  qcom,tx-device:
+$ref: /schemas/types.yaml#/definitions/phandle-array
+maxItems: 1
+description: A reference to Soundwire tx device phandle
+
+  qcom,rx-device:
+$ref: /schemas/types.yaml#/definitions/phandle-array
+maxItems: 1
+description: A reference to Soundwire rx device phandle
+
+  qcom,micbias1-microvolt:
+description: micbias1 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias2-microvolt:
+description: micbias2 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias3-microvolt:
+description: micbias3 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias4-microvolt:
+description: micbias4 voltage
+minimum: 180
+maximum: 285
+
+  qcom,mbhc-hphl-switch:
+description: Indicates that HPHL switch type is normally closed
+type: boolean
+
+  qcom,mbhc-ground-switch:
+description: Indicates that Headset Ground switch type is normally closed
+type: boolean
+
+  qcom,mbhc-button0-vthreshold-microvolt:
+description: Voltage threshold value headset button0
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button1-vthreshold-microvolt:
+description: Voltage threshold value headset button1
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button2-vthreshold-microvolt:
+description: Voltage threshold value headset button2
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button3-vthreshold-microvolt:
+description: Voltage threshold value headset button3
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button4-vthreshold-microvolt:
+description: Voltage threshold value headset button4
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button5-vthreshold-microvolt:
+description: Voltage threshold value headset button5
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button6-vthreshold-microvolt:
+description: Voltage threshold value headset button6
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button7-vthreshold-microvolt:
+description: Voltage threshold value headset button7
+minimum: 0
+maximum: 50
+
+  '#sound-dai-cells':
+const: 1
+
+required:
+  - compatible
+  - reset-gpios
+  - qcom,tx-device
+  - qcom,rx-device
+  - qcom,micbias1-microvolt
+  - qcom,micbias2-microvolt
+  - qcom,micbias3-microvolt
+  - qcom,micbias4-microvolt
+  - qcom,mbhc-hphl-switch
+  - qcom,mbhc-ground-switch
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+codec {
+compatible = "qcom,wcd9380-codec";
+reset-gpios = < 32 0>;
+#sound-dai-cells = <1>;
+qcom,tx-device = <_tx>;
+qcom,rx-device = <_rx>;
+qcom,micbias1-microvolt = <180>;
+qcom,micbias2-microvolt = <180>;
+qcom,micbias3-microvolt = <180>;
+qcom,micbias4-microvolt = <180>;
+qcom,mbhc-hphl-switch;
+qcom,mbhc-ground-switch;
+qcom,mbhc-button0-vthreshold-microvolt = <75000>;
+qcom,mbhc-button1-vthreshold-microvolt = <15>;
+qcom,mbhc-button2-vthreshold-microvolt = <237000>;
+qcom,mbhc-button3-vthreshold-microvolt = <50>;
+qcom,mbhc-button5-vthreshold-microvolt = <50>;
+qcom,mbhc-button6-vthreshold-microvolt = <50>;
+qcom,mbhc-button

[PATCH v4 0/9] ASoC: codecs: add wcd938x support

2021-04-14 Thread Srinivas Kandagatla
This patchset adds support for Qualcomm WCD938X codec.

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices, RX and
TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs and MBHC.

Eventhough this device has two SoundWire devices, only tx device has
access to main codec Control/Status Registers!

For codec driver to be functional it would need both tx and rx Soundwire devices
to be up and this is taken care by using device component framework and 
device-links
are used to ensure proper pm dependencies. Ex tx does not enter suspend
before rx or codec is suspended.

This patchset along with other SoundWire patches on the list
have been tested on SM8250 MTP device.

Am planning to send support for MBHC once this driver gets accepted!

Thanks,
srini

Many thanks for reviewing v3.

Changes since v3:
- Moved to using driver component framework
- Added device links to allow correct runtime PM
- added runtime pm support
- split codec bindings into two parts one for codec and other for soundwire 
device.
- 
Srinivas Kandagatla (9):
  ASoC: dt-bindings: wcd938x: add bindings for wcd938x
  ASoC: codecs: wcd-clsh: add new version support
  ASoC: codecs: wcd938x: add basic driver
  ASoC: dt-bindings: wcd938x-sdw: add bindings for wcd938x-sdw
  ASoC: codecs: wcd938x-sdw: add SoundWire driver
  ASoC: codecs: wcd938x: add basic controls
  ASoC: codecs: wcd938x: add playback dapm widgets
  ASoC: codecs: wcd938x: add capture dapm widgets
  ASoC: codecs: wcd938x: add audio routing

 .../bindings/sound/qcom,wcd938x-sdw.yaml  |   61 +
 .../bindings/sound/qcom,wcd938x.yaml  |  176 +
 sound/soc/codecs/Kconfig  |   13 +
 sound/soc/codecs/Makefile |4 +
 sound/soc/codecs/wcd-clsh-v2.c|  348 +-
 sound/soc/codecs/wcd-clsh-v2.h|   16 +
 sound/soc/codecs/wcd938x-sdw.c|  230 +
 sound/soc/codecs/wcd938x.c| 3786 +
 sound/soc/codecs/wcd938x.h|  670 +++
 9 files changed, 5294 insertions(+), 10 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

-- 
2.21.0



Re: [PATCH 4/5] ASoC: lpass: use the clock provider API

2021-04-12 Thread Srinivas Kandagatla




On 12/04/2021 13:17, Jerome Brunet wrote:

   -return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);
+   return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, >hw);

Now that we convert this to devm, You missed error path and driver remove
where we delete clk provider. This should be removed as well as part of
this patch.

Indeed. I should not have switched to devm here - It was not really the
purpose of the patch. Habits I guess.

Do you prefer I stick with devm (with the suggested fix) or revert to the
no-devm way for the v2 ? It makes no difference to me TBH.


devm should be good.

--srini




Re: [PATCH -next] nvmem: sprd: Add missing MODULE_DEVICE_TABLE

2021-04-12 Thread Srinivas Kandagatla




On 10/04/2021 04:50, Bixuan Cui wrote:

This patch adds missing MODULE_DEVICE_TABLE definition which generates
correct modalias for automatic loading of this driver when it is built
as an external module.

Reported-by: Hulk Robot 
Signed-off-by: Bixuan Cui 
---


Applied thanks,

--srini


  drivers/nvmem/sprd-efuse.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c
index 59523245db8a..5d394559edf2 100644
--- a/drivers/nvmem/sprd-efuse.c
+++ b/drivers/nvmem/sprd-efuse.c
@@ -425,6 +425,7 @@ static const struct of_device_id sprd_efuse_of_match[] = {
{ .compatible = "sprd,ums312-efuse", .data = _data },
{ }
  };
+MODULE_DEVICE_TABLE(of, sprd_efuse_of_match);
  
  static struct platform_driver sprd_efuse_driver = {

.probe = sprd_efuse_probe,



Re: [PATCH 4/5] ASoC: lpass: use the clock provider API

2021-04-12 Thread Srinivas Kandagatla

Thanks Jerome for the patch,


On 10/04/2021 12:13, Jerome Brunet wrote:

Clock providers should be registered using the clk_hw API.

Signed-off-by: Jerome Brunet 
---
  sound/soc/codecs/lpass-va-macro.c  | 2 +-
  sound/soc/codecs/lpass-wsa-macro.c | 9 +++--
  2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/sound/soc/codecs/lpass-va-macro.c 
b/sound/soc/codecs/lpass-va-macro.c
index 5294c57b2cd4..56b887301172 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -1343,7 +1343,7 @@ static int va_macro_register_fsgen_output(struct va_macro 
*va)
if (ret)
return ret;
  
-	return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);

+   return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, >hw);


Now that we convert this to devm, You missed error path and driver 
remove where we delete clk provider. This should be removed as well as 
part of this patch.



This applies to both wsa and va macro.

Thanks,
srini

  }
  
  static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,

diff --git a/sound/soc/codecs/lpass-wsa-macro.c 
b/sound/soc/codecs/lpass-wsa-macro.c
index e79a70386b4b..acb95e83c788 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -2337,10 +2337,9 @@ static const struct clk_ops swclk_gate_ops = {
.recalc_rate = swclk_recalc_rate,
  };
  
-static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)

+static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
  {
struct device *dev = wsa->dev;
-   struct device_node *np = dev->of_node;
const char *parent_clk_name;
const char *clk_name = "mclk";
struct clk_hw *hw;
@@ -2358,11 +2357,9 @@ static struct clk *wsa_macro_register_mclk_output(struct 
wsa_macro *wsa)
hw = >hw;
ret = clk_hw_register(wsa->dev, hw);
if (ret)
-   return ERR_PTR(ret);
-
-   of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+   return ret;
  
-	return NULL;

+   return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
  }
  
  static const struct snd_soc_component_driver wsa_macro_component_drv = {




Re: [RESEND PATCH] arm64: dts: qcom: sdm845-xiaomi-beryllium: Add audio support

2021-04-12 Thread Srinivas Kandagatla




On 07/04/2021 21:07, Joel Selvaraj wrote:

This patch adds audio support for Xiaomi Poco F1 phone. Phone's primary
Mic and 3.5mm Headphone jack are handled through the SDM845 sound card
and WCD9340 codec.

Tested-by: Amit Pundir 
Signed-off-by: Joel Selvaraj 
---
  .../boot/dts/qcom/sdm845-xiaomi-beryllium.dts | 117 ++
  1 file changed, 117 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts 
b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts
index 86cbae63eaf7..5b5786595cdb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts
@@ -5,6 +5,8 @@
  #include 
  #include 
  #include 
+#include 
+#include 
  #include "sdm845.dtsi"
  #include "pm8998.dtsi"
  #include "pmi8998.dtsi"
@@ -240,6 +242,28 @@ resin {
};
  };
  
+/* QUAT I2S Uses 1 I2S SD Line for audio on TAS2559/60 amplifiers */

+ {
+   qi2s@22 {
+   reg = <22>;
+   qcom,sd-lines = <0>;
+   };
+};
+
+ {
+   dai@0 {
+   reg = <0>;
+   };
+
+   dai@1 {
+   reg = <1>;
+   };
+
+   dai@2 {
+   reg = <2>;
+   };
+};
+
  _id_0 {
status = "okay";
  };
@@ -257,6 +281,73 @@ _2 {
cd-gpios = < 126 GPIO_ACTIVE_HIGH>;
  };
  
+ {

+   compatible = "qcom,db845c-sndcard";
+   pinctrl-0 = <_mi2s_active
+   _mi2s_sd0_active>;
+   pinctrl-names = "default";
+   model = "Xiaomi Poco F1";
+   audio-routing =
+   "RX_BIAS", "MCLK",
+   "AMIC1", "MIC BIAS1",
+   "AMIC2", "MIC BIAS2",
+   "AMIC3", "MIC BIAS3",
+   "MM_DL1",  "MultiMedia1 Playback",
+   "MM_DL2",  "MultiMedia2 Playback",
+   "MultiMedia3 Capture", "MM_UL3";


Overall the patch LGTM,

As Stephan Gerhold said these three lines are redundant.
Once removed, you could add

Reviewed-by: Srinivas Kandagatla 


--srini


+
+   mm1-dai-link {
+   link-name = "MultiMedia1";
+   cpu {
+   sound-dai = <  MSM_FRONTEND_DAI_MULTIMEDIA1>;
+   };
+   };
+
+   mm2-dai-link {
+   link-name = "MultiMedia2";
+   cpu {
+   sound-dai = <  MSM_FRONTEND_DAI_MULTIMEDIA2>;
+   };
+   };
+
+   mm3-dai-link {
+   link-name = "MultiMedia3";
+   cpu {
+   sound-dai = <  MSM_FRONTEND_DAI_MULTIMEDIA3>;
+   };
+   };
+
+   slim-dai-link {
+   link-name = "SLIM Playback";
+   cpu {
+   sound-dai = < SLIMBUS_0_RX>;
+   };
+
+   platform {
+   sound-dai = <>;
+   };
+
+   codec {
+   sound-dai =  < 0>;
+   };
+   };
+
+   slimcap-dai-link {
+   link-name = "SLIM Capture";
+   cpu {
+   sound-dai = < SLIMBUS_0_TX>;
+   };
+
+   platform {
+   sound-dai = <>;
+   };
+
+   codec {
+   sound-dai = < 1>;
+   };
+   };
+};
+
   {
gpio-reserved-ranges = <0 4>, <81 4>;
  
@@ -285,6 +376,15 @@ sdc2_card_det_n: sd-card-det-n {

function = "gpio";
bias-pull-up;
};
+
+   wcd_intr_default: wcd_intr_default {
+   pins = <54>;
+   function = "gpio";
+
+   input-enable;
+   bias-pull-down;
+   drive-strength = <2>;
+   };
  };
  
   {

@@ -345,6 +445,23 @@ _1_qmpphy {
vdda-pll-supply = <_l1a_0p875>;
  };
  
+{

+   pinctrl-0 = <_intr_default>;
+   pinctrl-names = "default";
+   clock-names = "extclk";
+   clocks = < RPMH_LN_BB_CLK2>;
+   reset-gpios = < 64 0>;
+   vdd-buck-supply = <_s4a_1p8>;
+   vdd-buck-sido-supply = <_s4a_1p8>;
+   vdd-tx-supply = <_s4a_1p8>;
+   vdd-rx-supply = <_s4a_1p8>;
+   vdd-io-supply = <_s4a_1p8>;
+   qcom,micbias1-microvolt = <270>;
+   qcom,micbias2-microvolt = <180>;
+   qcom,micbias3-microvolt = <270>;
+   qcom,micbias4-microvolt = <270>;
+};
+
   {
status = "okay";
  



Re: [PATCH v2] soundwire: qcom: wait for fifo space to be available before read/write

2021-04-01 Thread Srinivas Kandagatla




On 01/04/2021 15:36, Pierre-Louis Bossart wrote:



On 4/1/21 4:00 AM, Srinivas Kandagatla wrote:

If we write registers very fast we can endup in a situation where some
of the writes will be dropped without any notice.

So wait for the fifo space to be available before reading/writing the
soundwire registers.


Out of curiosity, do you actually need to do a check in the read case as 
well?


Yes, This is just to make sure the read command is finished and fifo is 
ready with data.


If not we will be reading quickly an empty fifo!



The commit message talks about writes getting dropped, is the opposite 
also a problem?


Its highly likely, for safety I have added support for both write and 
read waits in this patch.



--srini




[PATCH] soundwire: qcom: cleanup internal port config indexing

2021-04-01 Thread Srinivas Kandagatla
Internally used portconfig array for storing port bandwidth
params starts from offset zero. However port zero is not really
used and we also copy the bus parameters to offset zero.
So basically we endup with a code which has to subtract 1 from port
number to get to port parameters.

This is bit confusing to the reader so, make this bit more obvious by only
copying the parameters to offset 1 instead of zero. This will avoid doing
-1 every time when we try to get port params.

Similar thing has been recently done with din/dout_port_mask.

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 27 ++-
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 94fd58f9dda3..348d9a46f850 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -724,7 +724,7 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
int ret;
 
-   pcfg = >pconfig[params->port_num - 1];
+   pcfg = >pconfig[params->port_num];
 
value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
@@ -811,11 +811,11 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
struct qcom_swrm_port_config *pcfg;
struct sdw_slave *slave;
unsigned int m_port;
-   int i = 0;
+   int i = 1;
 
list_for_each_entry(m_rt, >m_rt_list, bus_node) {
list_for_each_entry(p_rt, _rt->port_list, port_node) {
-   pcfg = >pconfig[p_rt->num - 1];
+   pcfg = >pconfig[p_rt->num];
p_rt->transport_params.port_num = p_rt->num;
if (pcfg->word_length != SWR_INVALID_PARAM) {
sdw_fill_port_params(_rt->port_params,
@@ -832,7 +832,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
m_port = slave->m_port_map[p_rt->num];
/* port config starts at offset 0 so -1 from 
actual port number */
if (m_port)
-   pcfg = >pconfig[m_port - 1];
+   pcfg = >pconfig[m_port];
else
pcfg = >pconfig[i];
p_rt->transport_params.port_num = p_rt->num;
@@ -1167,15 +1167,16 @@ static int qcom_swrm_get_port_config(struct 
qcom_swrm_ctrl *ctrl)
of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, 
nports);
 
for (i = 0; i < nports; i++) {
-   ctrl->pconfig[i].si = si[i];
-   ctrl->pconfig[i].off1 = off1[i];
-   ctrl->pconfig[i].off2 = off2[i];
-   ctrl->pconfig[i].bp_mode = bp_mode[i];
-   ctrl->pconfig[i].hstart = hstart[i];
-   ctrl->pconfig[i].hstop = hstop[i];
-   ctrl->pconfig[i].word_length = word_length[i];
-   ctrl->pconfig[i].blk_group_count = blk_group_count[i];
-   ctrl->pconfig[i].lane_control = lane_control[i];
+   /* Valid port number range is from 1-14 */
+   ctrl->pconfig[i + 1].si = si[i];
+   ctrl->pconfig[i + 1].off1 = off1[i];
+   ctrl->pconfig[i + 1].off2 = off2[i];
+   ctrl->pconfig[i + 1].bp_mode = bp_mode[i];
+   ctrl->pconfig[i + 1].hstart = hstart[i];
+   ctrl->pconfig[i + 1].hstop = hstop[i];
+   ctrl->pconfig[i + 1].word_length = word_length[i];
+   ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i];
+   ctrl->pconfig[i + 1].lane_control = lane_control[i];
}
 
return 0;
-- 
2.21.0



[PATCH] soundwire: qcom: handle return correctly in qcom_swrm_transport_params

2021-04-01 Thread Srinivas Kandagatla
Looks like return from reg_write is set but not checked.
Fix this by adding error return path.

Reported-by: coverity-bot 
Addresses-Coverity-ID: 1503591 ("UNUSED_VALUE")
Fixes: 128eaf937adb ("soundwire: qcom: add support to missing transport params")
Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 5fd4a99cc8ac..348d9a46f850 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -731,17 +731,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
value |= pcfg->si;
 
ret = ctrl->reg_write(ctrl, reg, value);
+   if (ret)
+   goto err;
 
if (pcfg->lane_control != SWR_INVALID_PARAM) {
reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
value = pcfg->lane_control;
ret = ctrl->reg_write(ctrl, reg, value);
+   if (ret)
+   goto err;
}
 
if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
value = pcfg->blk_group_count;
ret = ctrl->reg_write(ctrl, reg, value);
+   if (ret)
+   goto err;
}
 
if (pcfg->hstart != SWR_INVALID_PARAM
@@ -755,11 +761,15 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
ret = ctrl->reg_write(ctrl, reg, value);
}
 
+   if (ret)
+   goto err;
+
if (pcfg->bp_mode != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
 
+err:
return ret;
 }
 
-- 
2.21.0



[PATCH v2] soundwire: qcom: wait for fifo space to be available before read/write

2021-04-01 Thread Srinivas Kandagatla
If we write registers very fast we can endup in a situation where some
of the writes will be dropped without any notice.

So wait for the fifo space to be available before reading/writing the
soundwire registers.

Signed-off-by: Srinivas Kandagatla 
---

Changes since v1:
merged some of the loop code to make it simple as suggested by Pierre
updated error code and comments as suggested by Vinod


 drivers/soundwire/qcom.c | 66 
 1 file changed, 66 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6affa3cd4039..5fd4a99cc8ac 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -24,6 +24,8 @@
 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK   BIT(1)
 #define SWRM_COMP_CFG_ENABLE_MSK   BIT(0)
 #define SWRM_COMP_PARAMS   0x100
+#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10)
+#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
 #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK   GENMASK(4, 0)
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK
GENMASK(9, 5)
 #define SWRM_INTERRUPT_STATUS  0x200
@@ -51,6 +53,8 @@
 #define SWRM_CMD_FIFO_CMD  0x308
 #define SWRM_CMD_FIFO_FLUSH0x1
 #define SWRM_CMD_FIFO_STATUS   0x30C
+#define SWRM_RD_CMD_FIFO_CNT_MASK  GENMASK(20, 16)
+#define SWRM_WR_CMD_FIFO_CNT_MASK  GENMASK(12, 8)
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
@@ -104,6 +108,7 @@
 #define SWR_BROADCAST_CMD_ID0x0F
 #define SWR_MAX_CMD_ID 14
 #define MAX_FIFO_RD_RETRY 3
+#define SWR_OVERFLOW_RETRY_COUNT 30
 
 struct qcom_swrm_port_config {
u8 si;
@@ -147,6 +152,8 @@ struct qcom_swrm_ctrl {
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status;
+   u32 wr_fifo_depth;
+   u32 rd_fifo_depth;
 };
 
 struct qcom_swrm_data {
@@ -238,6 +245,55 @@ static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
return val;
 }
 
+static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm)
+{
+   u32 fifo_outstanding_data, value;
+   int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
+
+   do {
+   /* Check for fifo underflow during read */
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_data = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, 
value);
+
+   /* Check if read data is available in read fifo */
+   if (fifo_outstanding_data > 0)
+   return 0;
+
+   usleep_range(500, 510);
+   } while (fifo_retry_count--);
+
+   if (fifo_outstanding_data == 0) {
+   dev_err_ratelimited(swrm->dev, "%s err read underflow\n", 
__func__);
+   return -EIO;
+   }
+
+   return 0;
+}
+
+static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm)
+{
+   u32 fifo_outstanding_cmds, value;
+   int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
+
+   do {
+   /* Check for fifo overflow during write */
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_cmds = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, 
value);
+
+   /* Check for space in write fifo before writing */
+   if (fifo_outstanding_cmds < swrm->wr_fifo_depth)
+   return 0;
+
+   usleep_range(500, 510);
+   } while (fifo_retry_count--);
+
+   if (fifo_outstanding_cmds == swrm->wr_fifo_depth) {
+   dev_err_ratelimited(swrm->dev, "%s err write overflow\n", 
__func__);
+   return -EIO;
+   }
+
+   return 0;
+}
 
 static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
 u8 dev_addr, u16 reg_addr)
@@ -256,6 +312,9 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl 
*swrm, u8 cmd_data,
  dev_addr, reg_addr);
}
 
+   if (swrm_wait_for_wr_fifo_avail(swrm))
+   return SDW_CMD_FAIL_OTHER;
+
/* Its assumed that write is okay as we do not get any status back */
swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
 
@@ -295,6 +354,9 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl 
*swrm,
/* wait for FIFO RD CMD complete to avoid overflow */
usleep_range(250, 255);
 
+   if (swrm_wait_

[PATCH 2/2] ASoC: codecs: lpass-rx-macro: set npl clock rate correctly

2021-03-31 Thread Srinivas Kandagatla
NPL clock rate is twice the MCLK rate, so set this correctly to
avoid soundwire timeouts.

Fixes: af3d54b99764 ("ASoC: codecs: lpass-rx-macro: add support for lpass rx 
macro")
Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/lpass-rx-macro.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/lpass-rx-macro.c 
b/sound/soc/codecs/lpass-rx-macro.c
index 8c04b3b2c907..7878da89d8e0 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -3551,7 +3551,7 @@ static int rx_macro_probe(struct platform_device *pdev)
 
/* set MCLK and NPL rates */
clk_set_rate(rx->clks[2].clk, MCLK_FREQ);
-   clk_set_rate(rx->clks[3].clk, MCLK_FREQ);
+   clk_set_rate(rx->clks[3].clk, 2 * MCLK_FREQ);
 
ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks);
if (ret)
-- 
2.21.0



[PATCH 1/2] ASoC: codecs: lpass-tx-macro: set npl clock rate correctly

2021-03-31 Thread Srinivas Kandagatla
NPL clock rate is twice the MCLK rate, so set this correctly to
avoid soundwire timeouts.

Fixes: c39667ddcfc5 ("ASoC: codecs: lpass-tx-macro: add support for lpass tx 
macro")
Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/lpass-tx-macro.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/lpass-tx-macro.c 
b/sound/soc/codecs/lpass-tx-macro.c
index 36d7a6442cdb..e8c6c738bbaa 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -1811,7 +1811,7 @@ static int tx_macro_probe(struct platform_device *pdev)
 
/* set MCLK and NPL rates */
clk_set_rate(tx->clks[2].clk, MCLK_FREQ);
-   clk_set_rate(tx->clks[3].clk, MCLK_FREQ);
+   clk_set_rate(tx->clks[3].clk, 2 * MCLK_FREQ);
 
ret = clk_bulk_prepare_enable(TX_NUM_CLKS_MAX, tx->clks);
if (ret)
-- 
2.21.0



[PATCH] soundwire: qcom: wait for fifo space to be available before read/write

2021-03-31 Thread Srinivas Kandagatla
If we write registers very fast we can endup in a situation where some
of the writes will be dropped without any notice.

So wait for the fifo space to be available before reading/writing the
soundwire registers.

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 74 
 1 file changed, 74 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6affa3cd4039..9b45717577f2 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -24,6 +24,8 @@
 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK   BIT(1)
 #define SWRM_COMP_CFG_ENABLE_MSK   BIT(0)
 #define SWRM_COMP_PARAMS   0x100
+#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10)
+#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
 #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK   GENMASK(4, 0)
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK
GENMASK(9, 5)
 #define SWRM_INTERRUPT_STATUS  0x200
@@ -51,6 +53,8 @@
 #define SWRM_CMD_FIFO_CMD  0x308
 #define SWRM_CMD_FIFO_FLUSH0x1
 #define SWRM_CMD_FIFO_STATUS   0x30C
+#define SWRM_RD_CMD_FIFO_CNT_MASK  GENMASK(20, 16)
+#define SWRM_WR_CMD_FIFO_CNT_MASK  GENMASK(12, 8)
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
@@ -104,6 +108,7 @@
 #define SWR_BROADCAST_CMD_ID0x0F
 #define SWR_MAX_CMD_ID 14
 #define MAX_FIFO_RD_RETRY 3
+#define SWR_OVERFLOW_RETRY_COUNT 30
 
 struct qcom_swrm_port_config {
u8 si;
@@ -147,6 +152,8 @@ struct qcom_swrm_ctrl {
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status;
+   u32 wr_fifo_depth;
+   u32 rd_fifo_depth;
 };
 
 struct qcom_swrm_data {
@@ -238,6 +245,63 @@ static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
return val;
 }
 
+static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm)
+{
+   u32 fifo_outstanding_cmd, value;
+   u8 fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
+
+   /* Check for fifo underflow during read */
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_cmd = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, value);
+
+/* Check number of outstanding commands in fifo before read */
+   if (fifo_outstanding_cmd)
+   return 0;
+
+   do {
+   usleep_range(500, 510);
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_cmd = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, 
value);
+   if (fifo_outstanding_cmd > 0)
+   break;
+   } while (fifo_retry_count--);
+
+   if (fifo_outstanding_cmd == 0) {
+   dev_err_ratelimited(swrm->dev, "%s err read underflow\n", 
__func__);
+   return -ENOMEM;
+   }
+
+   return 0;
+}
+
+static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm)
+{
+   u32 fifo_outstanding_cmd, value;
+   u8 fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
+
+   /* Check for fifo overflow during write */
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_cmd = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, value);
+
+   /* Check number of outstanding commands in fifo before write */
+   if (fifo_outstanding_cmd != swrm->wr_fifo_depth)
+   return 0;
+
+   do {
+   usleep_range(500, 510);
+   swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, );
+   fifo_outstanding_cmd = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, 
value);
+   if (fifo_outstanding_cmd < swrm->wr_fifo_depth)
+   break;
+   } while (fifo_retry_count--);
+
+   if (fifo_outstanding_cmd == swrm->wr_fifo_depth) {
+   dev_err_ratelimited(swrm->dev, "%s err write overflow\n", 
__func__);
+   return -ENOMEM;
+   }
+
+   return 0;
+}
 
 static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
 u8 dev_addr, u16 reg_addr)
@@ -256,6 +320,9 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl 
*swrm, u8 cmd_data,
  dev_addr, reg_addr);
}
 
+   if (swrm_wait_for_wr_fifo_avail(swrm))
+   return SDW_CMD_FAIL_OTHER;
+
/* Its assumed that write is okay as we do not get any status back */
swrm->reg_write(swrm, SWRM

Re: [PATCH v7 2/2] arm64: dts: qcom: Add sound node for sc7180-trogdor-coachz

2021-03-31 Thread Srinivas Kandagatla




On 14/03/2021 06:10, Srinivasa Rao Mandadapu wrote:

This is a trgodor variant, required to have sound node variable
for coachz specific platform.

Signed-off-by: Srinivasa Rao Mandadapu 
Reviewed-by: Stephen Boyd 
---


Reviewed-by: Srinivas Kandagatla 


  arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi | 10 ++
  1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi 
b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
index 4ad520f00485..e2ffe71c2d52 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
@@ -89,6 +89,16 @@ _out {
data-lanes = <0 1 2 3>;
  };
  
+ {

+   compatible = "google,sc7180-coachz";
+   model = "sc7180-adau7002-max98357a";
+   audio-routing = "PDM_DAT", "DMIC";
+};
+
+_multimedia0_codec {
+   sound-dai = <>;
+};
+
  /* PINCTRL - modifications to sc7180-trogdor.dtsi */
  
  _pp3300_dx_edp {




Re: [PATCH v7 1/2] arm64: dts: qcom: sc7180-trogdor: Add lpass dai link for I2S driver

2021-03-31 Thread Srinivas Kandagatla




On 14/03/2021 06:10, Srinivasa Rao Mandadapu wrote:

From: Ajit Pandey 

Add dai link for supporting lpass I2S driver, which is used
for audio capture and playback.
Add lpass-cpu node with  pin controls and i2s primary
and secondary dai-links

Signed-off-by: Ajit Pandey 
Signed-off-by: V Sujith Kumar Reddy 
Signed-off-by: Srinivasa Rao Mandadapu 
---



LGTM,

Reviewed-by: Srinivas Kandagatla 


  arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 58 
  1 file changed, 58 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi 
b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
index 436582279dad..fd345972a361 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
@@ -9,6 +9,7 @@
  #include 
  #include 
  #include 
+#include 
  
  /* PMICs depend on spmi_bus label and so must come after SoC */

  #include "pm6150.dtsi"
@@ -283,6 +284,42 @@ keyboard_backlight: keyboard-backlight {
max-brightness = <1023>;
};
};
+
+   sound: sound {
+   compatible = "google,sc7180-trogdor";
+   model = "sc7180-rt5682-max98357a-1mic";
+
+   audio-routing =
+   "Headphone Jack", "HPOL",
+   "Headphone Jack", "HPOR";
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   dai-link@0 {
+   link-name = "MultiMedia0";
+   reg = ;
+   cpu {
+   sound-dai = <_cpu MI2S_PRIMARY>;
+   };
+
+   sound_multimedia0_codec: codec {
+   sound-dai = < 0 /* aif1 */>;
+   };
+   };
+
+   dai-link@1 {
+   link-name = "MultiMedia1";
+   reg = ;
+   cpu {
+   sound-dai = <_cpu MI2S_SECONDARY>;
+   };
+
+   sound_multimedia1_codec: codec {
+   sound-dai = <>;
+   };
+   };
+   };
  };
  
   {

@@ -720,6 +757,27 @@  {
modem-init;
  };
  
+_cpu {

+   status = "okay";
+
+   pinctrl-names = "default";
+   pinctrl-0 = <_mi2s_active>, <_mi2s_active>, 
<_mi2s_mclk_active>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   mi2s@0 {
+   reg = ;
+   qcom,playback-sd-lines = <1>;
+   qcom,capture-sd-lines = <0>;
+   };
+
+   mi2s@1 {
+   reg = ;
+   qcom,playback-sd-lines = <0>;
+   };
+};
+
   {
status = "okay";
  };



[PATCH v6 9/9] soundwire: qcom: wait for enumeration to be complete in probe

2021-03-30 Thread Srinivas Kandagatla
Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index b1dbaf8263e5..b08ecb9b418c 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -123,6 +123,7 @@ struct qcom_swrm_ctrl {
struct regmap *regmap;
void __iomem *mmio;
struct completion broadcast;
+   struct completion enumeration;
struct work_struct slave_work;
/* Port alloc/free lock */
struct mutex port_lock;
@@ -418,6 +419,7 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus)
}
}
 
+   complete(>enumeration);
return 0;
 }
 
@@ -1139,6 +1141,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
dev_set_drvdata(>dev, ctrl);
mutex_init(>port_lock);
init_completion(>broadcast);
+   init_completion(>enumeration);
 
ctrl->bus.ops = _swrm_ops;
ctrl->bus.port_ops = _swrm_port_ops;
@@ -1185,6 +1188,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
}
 
qcom_swrm_init(ctrl);
+   wait_for_completion_timeout(>enumeration,
+   msecs_to_jiffies(TIMEOUT_MS));
ret = qcom_swrm_register_dais(ctrl);
if (ret)
goto err_master_add;
-- 
2.21.0



[PATCH v6 7/9] soundwire: export sdw_compare_devid, sdw_extract_slave_id and sdw_slave_add

2021-03-30 Thread Srinivas Kandagatla
Exporting these three functions makes sense as it can be used by
other controllers like Qualcomm during auto-enumeration!

Reported-by: kernel test robot 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/bus.c   | 4 +++-
 drivers/soundwire/slave.c | 1 +
 include/linux/soundwire/sdw.h | 2 ++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 9bd83c91a873..a9e0aa72654d 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, 
int i)
return NULL;
 }
 
-static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
+int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
 {
if (slave->id.mfg_id != id.mfg_id ||
slave->id.part_id != id.part_id ||
@@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, 
struct sdw_slave_id id)
 
return 0;
 }
+EXPORT_SYMBOL(sdw_compare_devid);
 
 /* called with bus_lock held */
 static int sdw_get_device_num(struct sdw_slave *slave)
@@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
"SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, 
unique_id 0x%x, version 0x%x\n",
id->class_id, id->mfg_id, id->part_id, id->unique_id, 
id->sdw_version);
 }
+EXPORT_SYMBOL(sdw_extract_slave_id);
 
 static int sdw_program_device_num(struct sdw_bus *bus)
 {
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index 112b21967c7a..0eed38a79c6d 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus,
 
return ret;
 }
+EXPORT_SYMBOL(sdw_slave_add);
 
 #if IS_ENABLED(CONFIG_ACPI)
 
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 350436db6ddb..5ff9a8f37e91 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -1039,5 +1039,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 
value);
 int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
 int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
 int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
+int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
+void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id 
*id);
 
 #endif /* __SOUNDWIRE_H */
-- 
2.21.0



[PATCH v6 8/9] soundwire: qcom: add auto enumeration support

2021-03-30 Thread Srinivas Kandagatla
Qualcomm SoundWire controller supports Auto Enumeration of the
devices within the IP. This patch enables support for this feature.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 86 +---
 1 file changed, 81 insertions(+), 5 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 1ad07784db4b..b1dbaf8263e5 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -57,6 +57,8 @@
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
 #define SWRM_RD_FIFO_CMD_ID_MASK   GENMASK(11, 8)
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
+#define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m)  (0x530 + 0x8 * (m))
+#define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m)  (0x534 + 0x8 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
 #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
@@ -143,6 +145,7 @@ struct qcom_swrm_ctrl {
enum sdw_slave_status status[SDW_MAX_DEVICES];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
+   u32 slave_status;
 };
 
 struct qcom_swrm_data {
@@ -343,6 +346,7 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
int i;
 
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+   ctrl->slave_status = val;
 
for (i = 0; i < SDW_MAX_DEVICES; i++) {
u32 s;
@@ -353,10 +357,74 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
}
 }
 
+static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus,
+   struct sdw_slave *slave, int devnum)
+{
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   u32 status;
+
+   ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+   status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ));
+   status &= SWRM_MCP_SLV_STATUS_MASK;
+
+   if (status == SDW_SLAVE_ATTACHED) {
+   if (slave)
+   slave->dev_num = devnum;
+   mutex_lock(>bus_lock);
+   set_bit(devnum, bus->assigned);
+   mutex_unlock(>bus_lock);
+   }
+}
+
+static int qcom_swrm_enumerate(struct sdw_bus *bus)
+{
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   struct sdw_slave *slave, *_s;
+   struct sdw_slave_id id;
+   u32 val1, val2;
+   bool found;
+   u64 addr;
+   int i;
+   char *buf1 = (char *), *buf2 = (char *)
+
+   for (i = 1; i <= SDW_MAX_DEVICES; i++) {
+   /*SCP_Devid5 - Devid 4*/
+   ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), );
+
+   /*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/
+   ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), );
+
+   if (!val1 && !val2)
+   break;
+
+   addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) |
+   ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) |
+   ((u64)buf1[0] << 40);
+
+   sdw_extract_slave_id(bus, addr, );
+   found = false;
+   /* Now compare with entries */
+   list_for_each_entry_safe(slave, _s, >slaves, node) {
+   if (sdw_compare_devid(slave, id) == 0) {
+   qcom_swrm_set_slave_dev_num(bus, slave, i);
+   found = true;
+   break;
+   }
+   }
+
+   if (!found) {
+   qcom_swrm_set_slave_dev_num(bus, NULL, i);
+   sdw_slave_add(bus, , NULL);
+   }
+   }
+
+   return 0;
+}
+
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
struct qcom_swrm_ctrl *swrm = dev_id;
-   u32 value, intr_sts, intr_sts_masked;
+   u32 value, intr_sts, intr_sts_masked, slave_status;
u32 i;
u8 devnum = 0;
int ret = IRQ_HANDLED;
@@ -385,8 +453,15 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void 
*dev_id)
case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
dev_err_ratelimited(swrm->dev, "%s: SWR new 
slave attached\n",
__func__);
-   qcom_swrm_get_device_status(swrm);
-   sdw_handle_slave_status(>bus, 
swrm->status);
+   swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, 
_status);
+   if (swrm->slave_status 

[PATCH v6 6/9] soundwire: qcom: add support to new interrupts

2021-03-30 Thread Srinivas Kandagatla
Add support to new interrupts which includes reporting some of the
error interrupts and adding support to SLAVE pending interrupt!

This patch also changes the interrupt handler behaviour on handling
any pending interrupts by checking it before returning out of irq handler.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 161 ---
 1 file changed, 135 insertions(+), 26 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index faa4c84dcf61..1ad07784db4b 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -28,10 +28,21 @@
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK
GENMASK(9, 5)
 #define SWRM_INTERRUPT_STATUS  0x200
 #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
+#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ   BIT(0)
 #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED   BIT(1)
 #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
+#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOWBIT(5)
+#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6)
 #define SWRM_INTERRUPT_STATUS_CMD_ERRORBIT(7)
+#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION  BIT(8)
+#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCHBIT(9)
 #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED  BIT(10)
+#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13)
+#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2  BIT(14)
+#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP   BIT(16)
+#define SWRM_INTERRUPT_MAX 17
 #define SWRM_INTERRUPT_MASK_ADDR   0x204
 #define SWRM_INTERRUPT_CLEAR   0x208
 #define SWRM_INTERRUPT_CPU_EN  0x210
@@ -58,6 +69,7 @@
 #define SWRM_MCP_STATUS_BANK_NUM_MASK  BIT(0)
 #define SWRM_MCP_SLV_STATUS0x1090
 #define SWRM_MCP_SLV_STATUS_MASK   GENMASK(1, 0)
+#define SWRM_MCP_SLV_STATUS_SZ 2
 #define SWRM_DP_PORT_CTRL_BANK(n, m)   (0x1124 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL_1(n)(0x112C + 0x100 * (n - 1))
@@ -123,6 +135,7 @@ struct qcom_swrm_ctrl {
int rows_index;
unsigned long dout_port_mask;
unsigned long din_port_mask;
+   u32 intr_mask;
u8 rcmd_id;
u8 wcmd_id;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -305,6 +318,25 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl 
*swrm,
return SDW_CMD_IGNORED;
 }
 
+static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
+{
+   u32 val, status;
+   int dev_num;
+
+   ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+
+   for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) {
+   status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
+
+   if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
+   ctrl->status[dev_num] = status;
+   return dev_num;
+   }
+   }
+
+   return -EINVAL;
+}
+
 static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
 {
u32 val;
@@ -323,36 +355,112 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
 
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
-   struct qcom_swrm_ctrl *ctrl = dev_id;
-   u32 sts, value;
+   struct qcom_swrm_ctrl *swrm = dev_id;
+   u32 value, intr_sts, intr_sts_masked;
+   u32 i;
+   u8 devnum = 0;
+   int ret = IRQ_HANDLED;
 
-   ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, );
+   swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, _sts);
+   intr_sts_masked = intr_sts & swrm->intr_mask;
 
-   if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) {
-   ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, );
-   dev_err_ratelimited(ctrl->dev,
-   "CMD error, fifo status 0x%x\n",
-value);
-   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
-   }
-
-   if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
-   sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) {
-   qcom_swrm_get_device_status(ctrl);
-   sdw_handle_slave_status(>bus, ctrl->s

[PATCH v6 5/9] soundwire: qcom: update register read/write routine

2021-03-30 Thread Srinivas Kandagatla
In the existing code every soundwire register read and register write
are kinda blocked. Each of these are using a special command id that
generates interrupt after it successfully finishes. This is really
overhead, limiting and not really necessary unless we are doing
something special.

We can simply read/write the fifo that should also give exactly
what we need! This will also allow to read/write registers in
interrupt context, which was not possible with the special
command approach.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
 21: 130 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
 21: 3 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

This has significantly not only reduced interrupting CPU during enumeration
but also during streaming!

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 179 ++-
 1 file changed, 100 insertions(+), 79 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 0f2167433d2f..faa4c84dcf61 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -38,11 +38,13 @@
 #define SWRM_CMD_FIFO_WR_CMD   0x300
 #define SWRM_CMD_FIFO_RD_CMD   0x304
 #define SWRM_CMD_FIFO_CMD  0x308
+#define SWRM_CMD_FIFO_FLUSH0x1
 #define SWRM_CMD_FIFO_STATUS   0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
+#define SWRM_RD_FIFO_CMD_ID_MASK   GENMASK(11, 8)
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
@@ -78,13 +80,16 @@
 #define SWRM_SPECIAL_CMD_ID0xF
 #define MAX_FREQ_NUM   1
 #define TIMEOUT_MS (2 * HZ)
-#define QCOM_SWRM_MAX_RD_LEN   0xf
+#define QCOM_SWRM_MAX_RD_LEN   0x1
 #define QCOM_SDW_MAX_PORTS 14
 #define DEFAULT_CLK_FREQ   960
 #define SWRM_MAX_DAIS  0xF
 #define SWR_INVALID_PARAM 0xFF
 #define SWR_HSTOP_MAX_VAL 0xF
 #define SWR_HSTART_MIN_VAL 0x0
+#define SWR_BROADCAST_CMD_ID0x0F
+#define SWR_MAX_CMD_ID 14
+#define MAX_FIFO_RD_RETRY 3
 
 struct qcom_swrm_port_config {
u8 si;
@@ -103,10 +108,8 @@ struct qcom_swrm_ctrl {
struct device *dev;
struct regmap *regmap;
void __iomem *mmio;
-   struct completion *comp;
+   struct completion broadcast;
struct work_struct slave_work;
-   /* read/write lock */
-   spinlock_t comp_lock;
/* Port alloc/free lock */
struct mutex port_lock;
struct clk *hclk;
@@ -120,6 +123,8 @@ struct qcom_swrm_ctrl {
int rows_index;
unsigned long dout_port_mask;
unsigned long din_port_mask;
+   u8 rcmd_id;
+   u8 wcmd_id;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES];
@@ -198,77 +203,106 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl 
*ctrl, int reg,
return SDW_CMD_OK;
 }
 
-static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
-u8 dev_addr, u16 reg_addr)
+static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
+  u8 dev_addr, u16 reg_addr)
 {
-   DECLARE_COMPLETION_ONSTACK(comp);
-   unsigned long flags;
u32 val;
-   int ret;
-
-   spin_lock_irqsave(>comp_lock, flags);
-   ctrl->comp = 
-   spin_unlock_irqrestore(>comp_lock, flags);
-   val = SWRM_REG_VAL_PACK(cmd_data, dev_addr,
-   SWRM_SPECIAL_CMD_ID, reg_addr);
-   ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val);
-   if (ret)
-   goto err;
-
-   ret = wait_for_completion_timeout(ctrl->comp,
- msecs_to_jiffies(TIMEOUT_MS));
+   u8 id = *cmd_id;
 
-   if (!ret)
-   ret = SDW_CMD_IGNORED;
-   else
-   ret = SDW_CMD_OK;
-err:
-   spin_lock_irqsave(>comp_lock, flags);
-   ctrl->comp = NULL;
-   spin_unlock_irqrestore(>comp_lock, flags);
+   if (id != SWR_BROADCAST_CMD_ID) {
+   if (id < SWR_MAX_CMD_ID)
+   id += 1;
+   else
+   id = 0;
+

[PATCH v6 3/9] soundwire: qcom: set continue execution flag for ignored commands

2021-03-30 Thread Srinivas Kandagatla
version 1.5.1 and higher IPs of this controller required to set
continue execution on ignored command flag. This patch sets this flag.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index fdcb8ffb4284..edc77d18c245 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -40,6 +40,7 @@
 #define SWRM_CMD_FIFO_CMD  0x308
 #define SWRM_CMD_FIFO_STATUS   0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
+#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
@@ -343,7 +344,15 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
/* Configure number of retries of a read/write cmd */
-   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES);
+   if (ctrl->version > 0x01050001) {
+   /* Only for versions >= 1.5.1 */
+   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+   SWRM_RD_WR_CMD_RETRIES |
+   SWRM_CONTINUE_EXEC_ON_CMD_IGNORE);
+   } else {
+   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+   SWRM_RD_WR_CMD_RETRIES);
+   }
 
/* Set IRQ to PULSE */
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
-- 
2.21.0



[PATCH v6 2/9] soundwire: qcom: add support to missing transport params

2021-03-30 Thread Srinivas Kandagatla
Some of the transport parameters derived from device tree
are not fully parsed by the driver.

This patch adds support to parse those missing parameters.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 106 ++-
 1 file changed, 94 insertions(+), 12 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 277f711e374d..fdcb8ffb4284 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -54,7 +54,13 @@
 #define SWRM_MCP_SLV_STATUS0x1090
 #define SWRM_MCP_SLV_STATUS_MASK   GENMASK(1, 0)
 #define SWRM_DP_PORT_CTRL_BANK(n, m)   (0x1124 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_BLOCK_CTRL_1(n)(0x112C + 0x100 * (n - 1))
+#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_HCTRL_BANK(n, m)  (0x1134 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DIN_DPn_PCM_PORT_CTRL(n)  (0x1054 + 0x100 * (n - 1))
+
 #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
@@ -73,12 +79,20 @@
 #define QCOM_SDW_MAX_PORTS 14
 #define DEFAULT_CLK_FREQ   960
 #define SWRM_MAX_DAIS  0xF
+#define SWR_INVALID_PARAM 0xFF
+#define SWR_HSTOP_MAX_VAL 0xF
+#define SWR_HSTART_MIN_VAL 0x0
 
 struct qcom_swrm_port_config {
u8 si;
u8 off1;
u8 off2;
u8 bp_mode;
+   u8 hstart;
+   u8 hstop;
+   u8 word_length;
+   u8 blk_group_count;
+   u8 lane_control;
 };
 
 struct qcom_swrm_ctrl {
@@ -396,8 +410,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
 struct sdw_port_params *p_params,
 unsigned int bank)
 {
-   /* TBD */
-   return 0;
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+
+   return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num),
+  p_params->bps - 1);
+
 }
 
 static int qcom_swrm_transport_params(struct sdw_bus *bus,
@@ -405,20 +422,45 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
  enum sdw_reg_bank bank)
 {
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   struct qcom_swrm_port_config *pcfg;
u32 value;
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
int ret;
 
-   value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
-   value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
-   value |= params->sample_interval - 1;
+   pcfg = >pconfig[params->port_num - 1];
+
+   value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
+   value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
+   value |= pcfg->si;
 
ret = ctrl->reg_write(ctrl, reg, value);
 
-   if (!ret && params->blk_pkg_mode) {
-   reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+   if (pcfg->lane_control != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
+   value = pcfg->lane_control;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
 
-   ret = ctrl->reg_write(ctrl, reg, 1);
+   if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
+   value = pcfg->blk_group_count;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
+
+   if (pcfg->hstart != SWR_INVALID_PARAM
+   && pcfg->hstop != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+   value = (pcfg->hstop << 4) | pcfg->hstart;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   } else {
+   reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+   value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
+
+   if (pcfg->bp_mode != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+   ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
 
return ret;
@@ -466,10 +508,13 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
list_for_each_entry(p_rt, _rt->port_list, port_node) {
pcfg = >pconfig[p_rt->num - 1];
p_rt->transport_par

[PATCH v6 4/9] soundwire: qcom: start the clock during initialization

2021-03-30 Thread Srinivas Kandagatla
Start the clock during initialization, doing this explicitly
will add more clarity when we are adding clock stop feature.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index edc77d18c245..0f2167433d2f 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -47,6 +47,8 @@
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
 #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
+#define SWRM_MCP_BUS_CTRL  0x1044
+#define SWRM_MCP_BUS_CLK_START BIT(1)
 #define SWRM_MCP_CFG_ADDR  0x1048
 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK  GENMASK(21, 17)
 #define SWRM_DEF_CMD_NO_PINGS  0x1f
@@ -343,6 +345,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32p_replace_bits(, SWRM_DEF_CMD_NO_PINGS, 
SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
+   ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
/* Configure number of retries of a read/write cmd */
if (ctrl->version > 0x01050001) {
/* Only for versions >= 1.5.1 */
-- 
2.21.0



[PATCH v6 1/9] dt-bindings: soundwire: qcom: clarify data port bus parameters

2021-03-30 Thread Srinivas Kandagatla
Some of the parameters for data ports are not applicable or not implemented
in IP. So mark them as invalid/not applicable in DT so that controller is
aware of this.

Add comment to these bindings to provide more clarity on the values!

Signed-off-by: Srinivas Kandagatla 
Acked-by: Rob Herring 
Reviewed-by: Pierre-Louis Bossart 
---
 .../bindings/soundwire/qcom,sdw.txt   | 20 +++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt 
b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
index b104be131235..b93a2b3e029d 100644
--- a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
+++ b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
@@ -54,6 +54,8 @@ board specific bus parameters.
Value type: 
Definition: should specify payload transport window offset1 of each
data port. Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-offset2:
@@ -61,6 +63,8 @@ board specific bus parameters.
Value type: 
Definition: should specify payload transport window offset2 of each
data port. Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-sinterval-low:
@@ -69,12 +73,16 @@ board specific bus parameters.
Definition: should be sample interval low of each data port.
Out ports followed by In ports. Used for Sample Interval
calculation.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-word-length:
Usage: optional
Value type: 
Definition: should be size of payload channel sample.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-block-pack-mode:
@@ -84,6 +92,8 @@ board specific bus parameters.
0 to indicate Blocks are per Channel
1 to indicate Blocks are per Port.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-block-group-count:
@@ -92,6 +102,8 @@ board specific bus parameters.
Definition: should be in range 1 to 4 to indicate how many sample
intervals are combined into a payload.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-lane-control:
@@ -100,6 +112,8 @@ board specific bus parameters.
Definition: should be in range 0 to 7 to identify which data lane
the data port uses.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-hstart:
@@ -109,6 +123,8 @@ board specific bus parameters.
SoundWire Frame, i.e. left edge of the Transport sub-frame
for each port. Values between 0 and 15 are valid.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-hstop:
@@ -118,6 +134,8 @@ board specific bus parameters.
SoundWire Frame, i.e. the right edge of the Transport
sub-frame for each port. Values between 0 and 15 are valid.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,dports-type:
@@ -128,6 +146,8 @@ board specific bus parameters.
1 for simple ports

[PATCH v6 0/9] soundwire: qcom: various improvements

2021-03-30 Thread Srinivas Kandagatla
Thanks for reviewing v5 of this patchset!

During testing SoundWire controller on SM8250 MTP, we found
few issues like all the interrupts are not handled,
all transport parameters are not read from device tree.
Patch to add Auto Enumeration supported by the controller
is also part of this series.

Other major issue was register read/writes which was interrupt based
was an overhead and puts lot of limitation on context it can be used from.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
21: 130 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
21: 3 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

So this patchset add various improvements to the existing driver
to address above issues.

Tested it on SM8250 MTP with 2x WSA881x speakers, HeadPhones on
WCD938x via lpass-rx-macro and Analog MICs via lpass-tx-macro.
Also tested on DragonBoard DB845c with 2xWSA881x speakers.

Changes since v5:
- Use BIT macro in interrupt routine
- add comment for fifo write

Srinivas Kandagatla (9):
  dt-bindings: soundwire: qcom: clarify data port bus parameters
  soundwire: qcom: add support to missing transport params
  soundwire: qcom: set continue execution flag for ignored commands
  soundwire: qcom: start the clock during initialization
  soundwire: qcom: update register read/write routine
  soundwire: qcom: add support to new interrupts
  soundwire: export sdw_compare_devid, sdw_extract_slave_id and
sdw_slave_add
  soundwire: qcom: add auto enumeration support
  soundwire: qcom: wait for enumeration to be complete in probe

 .../bindings/soundwire/qcom,sdw.txt   |  20 +
 drivers/soundwire/bus.c   |   4 +-
 drivers/soundwire/qcom.c  | 529 ++
 drivers/soundwire/slave.c |   1 +
 include/linux/soundwire/sdw.h |   2 +
 5 files changed, 443 insertions(+), 113 deletions(-)

-- 
2.21.0



[PATCH 10/10] nvmem: qfprom: Add support for fuse blowing on sc7280

2021-03-30 Thread Srinivas Kandagatla
From: Rajendra Nayak 

Handle the differences across LDO voltage needed for blowing fuses,
and the blow timer value, identified using a minor version of 15
on sc7280.

Signed-off-by: Rajendra Nayak 
Signed-off-by: Ravi Kumar Bokka 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/qfprom.c | 27 +--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 100d69d8f2e1..d6d3f24685a8 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -45,11 +45,13 @@ MODULE_PARM_DESC(read_raw_data, "Read raw instead of 
corrected data");
  * @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow.
  * @qfprom_blow_set_freq:The frequency required to set when we start the
  *   fuse blowing.
+ * @qfprom_blow_uV:  LDO voltage to be set when doing efuse blow
  */
 struct qfprom_soc_data {
u32 accel_value;
u32 qfprom_blow_timer_value;
u32 qfprom_blow_set_freq;
+   int qfprom_blow_uV;
 };
 
 /**
@@ -111,6 +113,15 @@ static const struct qfprom_soc_compatible_data 
sc7180_qfprom = {
.nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout)
 };
 
+static const struct nvmem_keepout sc7280_qfprom_keepout[] = {
+   {.start = 0x128, .end = 0x148},
+   {.start = 0x238, .end = 0x248}
+};
+
+static const struct qfprom_soc_compatible_data sc7280_qfprom = {
+   .keepout = sc7280_qfprom_keepout,
+   .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout)
+};
 /**
  * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
  * @priv: Our driver data.
@@ -168,6 +179,7 @@ static int qfprom_enable_fuse_blowing(const struct 
qfprom_priv *priv,
  struct qfprom_touched_values *old)
 {
int ret;
+   int qfprom_blow_uV = priv->soc_data->qfprom_blow_uV;
 
ret = clk_prepare_enable(priv->secclk);
if (ret) {
@@ -187,9 +199,9 @@ static int qfprom_enable_fuse_blowing(const struct 
qfprom_priv *priv,
 * a rail shared do don't specify a max--regulator constraints
 * will handle.
 */
-   ret = regulator_set_voltage(priv->vcc, 180, INT_MAX);
+   ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX);
if (ret) {
-   dev_err(priv->dev, "Failed to set 1.8 voltage\n");
+   dev_err(priv->dev, "Failed to set %duV\n", qfprom_blow_uV);
goto err_clk_rate_set;
}
 
@@ -311,6 +323,14 @@ static const struct qfprom_soc_data qfprom_7_8_data = {
.accel_value = 0xD10,
.qfprom_blow_timer_value = 25,
.qfprom_blow_set_freq = 480,
+   .qfprom_blow_uV = 180,
+};
+
+static const struct qfprom_soc_data qfprom_7_15_data = {
+   .accel_value = 0xD08,
+   .qfprom_blow_timer_value = 24,
+   .qfprom_blow_set_freq = 480,
+   .qfprom_blow_uV = 190,
 };
 
 static int qfprom_probe(struct platform_device *pdev)
@@ -379,6 +399,8 @@ static int qfprom_probe(struct platform_device *pdev)
 
if (major_version == 7 && minor_version == 8)
priv->soc_data = _7_8_data;
+   if (major_version == 7 && minor_version == 15)
+   priv->soc_data = _7_15_data;
 
priv->vcc = devm_regulator_get(>dev, "vcc");
if (IS_ERR(priv->vcc))
@@ -405,6 +427,7 @@ static int qfprom_probe(struct platform_device *pdev)
 static const struct of_device_id qfprom_of_match[] = {
{ .compatible = "qcom,qfprom",},
{ .compatible = "qcom,sc7180-qfprom", .data = _qfprom},
+   { .compatible = "qcom,sc7280-qfprom", .data = _qfprom},
{/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, qfprom_of_match);
-- 
2.21.0



[PATCH 07/10] nvmem: core: Fix unintentional sign extension issue

2021-03-30 Thread Srinivas Kandagatla
From: Colin Ian King 

The shifting of the u8 integer buf[3] by 24 bits to the left will
be promoted to a 32 bit signed int and then sign-extended to a
u64. In the event that the top bit of buf[3] is set then all
then all the upper 32 bits of the u64 end up as also being set
because of the sign-extension. Fix this by casting buf[i] to
a u64 before the shift.

Addresses-Coverity: ("Unintended sign extension")
Fixes: 097eb1136ebb ("nvmem: core: Add functions to make number reading easy")
Signed-off-by: Colin Ian King 
Reviewed-by: Douglas Anderson 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 635e3131eb5f..bca671ff4e54 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1693,7 +1693,7 @@ int nvmem_cell_read_variable_le_u64(struct device *dev, 
const char *cell_id,
/* Copy w/ implicit endian conversion */
*val = 0;
for (i = 0; i < len; i++)
-   *val |= buf[i] << (8 * i);
+   *val |= (uint64_t)buf[i] << (8 * i);
 
kfree(buf);
 
-- 
2.21.0



[PATCH 06/10] nvmem: core: Add functions to make number reading easy

2021-03-30 Thread Srinivas Kandagatla
From: Douglas Anderson 

Sometimes the clients of nvmem just want to get a number out of
nvmem. They don't want to think about exactly how many bytes the nvmem
cell took up. They just want the number. Let's make it easy.

In general this concept is useful because nvmem space is precious and
usually the fewest bits are allocated that will hold a given value on
a given system. However, even though small numbers might be fine on
one system that doesn't mean that logically the number couldn't be
bigger. Imagine nvmem containing a max frequency for a component. On
one system perhaps that fits in 16 bits. On another system it might
fit in 32 bits. The code reading this number doesn't care--it just
wants the number.

We'll provide two functions: nvmem_cell_read_variable_le_u32() and
nvmem_cell_read_variable_le_u64().

Comparing these to the existing functions like nvmem_cell_read_u32():
* These new functions have no problems if the value was stored in
  nvmem in fewer bytes. It's OK to use these function as long as the
  value stored will fit in 32-bits (or 64-bits).
* These functions avoid problems that the earlier APIs had with bit
  offsets. For instance, you can't use nvmem_cell_read_u32() to read a
  value has nbits=32 and bit_offset=4 because the nvmem cell must be
  at least 5 bytes big to hold this value. The new API accounts for
  this and works fine.
* These functions make it very explicit that they assume that the
  number was stored in little endian format. The old functions made
  this assumption whenever bit_offset was non-zero (see
  nvmem_shift_read_buffer_in_place()) but didn't whenever the
  bit_offset was zero.

NOTE: it's assumed that we don't need an 8-bit or 16-bit version of
this function. The 32-bit version of the function can be used to read
8-bit or 16-bit data.

At the moment, I'm only adding the "unsigned" versions of these
functions, but if it ends up being useful someone could add a "signed"
version that did 2's complement sign extension.

At the moment, I'm only adding the "little endian" versions of these
functions. Adding the "big endian" version would require adding "big
endian" support to nvmem_shift_read_buffer_in_place().

Signed-off-by: Douglas Anderson 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/core.c   | 95 ++
 include/linux/nvmem-consumer.h |  4 ++
 2 files changed, 99 insertions(+)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index a5ab1e0c74cf..635e3131eb5f 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1606,6 +1606,101 @@ int nvmem_cell_read_u64(struct device *dev, const char 
*cell_id, u64 *val)
 }
 EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
 
+static void *nvmem_cell_read_variable_common(struct device *dev,
+const char *cell_id,
+size_t max_len, size_t *len)
+{
+   struct nvmem_cell *cell;
+   int nbits;
+   void *buf;
+
+   cell = nvmem_cell_get(dev, cell_id);
+   if (IS_ERR(cell))
+   return cell;
+
+   nbits = cell->nbits;
+   buf = nvmem_cell_read(cell, len);
+   nvmem_cell_put(cell);
+   if (IS_ERR(buf))
+   return buf;
+
+   /*
+* If nbits is set then nvmem_cell_read() can significantly exaggerate
+* the length of the real data. Throw away the extra junk.
+*/
+   if (nbits)
+   *len = DIV_ROUND_UP(nbits, 8);
+
+   if (*len > max_len) {
+   kfree(buf);
+   return ERR_PTR(-ERANGE);
+   }
+
+   return buf;
+}
+
+/**
+ * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little 
endian number.
+ *
+ * @dev: Device that requests the nvmem cell.
+ * @cell_id: Name of nvmem cell to read.
+ * @val: pointer to output value.
+ *
+ * Return: 0 on success or negative errno.
+ */
+int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
+   u32 *val)
+{
+   size_t len;
+   u8 *buf;
+   int i;
+
+   buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), );
+   if (IS_ERR(buf))
+   return PTR_ERR(buf);
+
+   /* Copy w/ implicit endian conversion */
+   *val = 0;
+   for (i = 0; i < len; i++)
+   *val |= buf[i] << (8 * i);
+
+   kfree(buf);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
+
+/**
+ * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little 
endian number.
+ *
+ * @dev: Device that requests the nvmem cell.
+ * @cell_id: Name of nvmem cell to read.
+ * @val: pointer to output value.
+ *
+ * Return: 0 on success or negative errno.
+ */
+int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
+   u64 *val)
+{
+   size_t len;
+   u8 *buf;
+   int i;
+
+

[PATCH 09/10] dt-bindings: nvmem: Add SoC compatible for sc7280

2021-03-30 Thread Srinivas Kandagatla
From: Rajendra Nayak 

Document SoC compatible for sc7280

Signed-off-by: Rajendra Nayak 
Acked-by: Rob Herring 
Signed-off-by: Srinivas Kandagatla 
---
 Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml 
b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 992777c90a0b..861b205016b1 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -24,6 +24,7 @@ properties:
   - qcom,msm8998-qfprom
   - qcom,qcs404-qfprom
   - qcom,sc7180-qfprom
+  - qcom,sc7280-qfprom
   - qcom,sdm845-qfprom
   - const: qcom,qfprom
 
-- 
2.21.0



[PATCH 05/10] nvmem: brcm_nvram: new driver exposing Broadcom's NVRAM

2021-03-30 Thread Srinivas Kandagatla
From: Rafał Miłecki 

This driver provides access to Broadcom's NVRAM.

Signed-off-by: Rafał Miłecki 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/Kconfig  |  9 +
 drivers/nvmem/Makefile |  2 +
 drivers/nvmem/brcm_nvram.c | 78 ++
 3 files changed, 89 insertions(+)
 create mode 100644 drivers/nvmem/brcm_nvram.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 75d2594c16e1..642ddc699fd1 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -278,4 +278,13 @@ config NVMEM_RMEM
 
  This driver can also be built as a module. If so, the module
  will be called nvmem-rmem.
+
+config NVMEM_BRCM_NVRAM
+   tristate "Broadcom's NVRAM support"
+   depends on ARCH_BCM_5301X || COMPILE_TEST
+   depends on HAS_IOMEM
+   help
+ This driver provides support for Broadcom's NVRAM that can be accessed
+ using I/O mapping.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 5376b8e0dae5..bbea1410240a 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -57,3 +57,5 @@ obj-$(CONFIG_SPRD_EFUSE)  += nvmem_sprd_efuse.o
 nvmem_sprd_efuse-y := sprd-efuse.o
 obj-$(CONFIG_NVMEM_RMEM)   += nvmem-rmem.o
 nvmem-rmem-y   := rmem.o
+obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
+nvmem_brcm_nvram-y := brcm_nvram.o
diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c
new file mode 100644
index ..bd2ecaaf4585
--- /dev/null
+++ b/drivers/nvmem/brcm_nvram.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct brcm_nvram {
+   struct device *dev;
+   void __iomem *base;
+};
+
+static int brcm_nvram_read(void *context, unsigned int offset, void *val,
+  size_t bytes)
+{
+   struct brcm_nvram *priv = context;
+   u8 *dst = val;
+
+   while (bytes--)
+   *dst++ = readb(priv->base + offset++);
+
+   return 0;
+}
+
+static int brcm_nvram_probe(struct platform_device *pdev)
+{
+   struct nvmem_config config = {
+   .name = "brcm-nvram",
+   .reg_read = brcm_nvram_read,
+   };
+   struct device *dev = >dev;
+   struct resource *res;
+   struct brcm_nvram *priv;
+
+   priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+   if (!priv)
+   return -ENOMEM;
+   priv->dev = dev;
+
+   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   priv->base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(priv->base))
+   return PTR_ERR(priv->base);
+
+   config.dev = dev;
+   config.priv = priv;
+   config.size = resource_size(res);
+
+   return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, ));
+}
+
+static const struct of_device_id brcm_nvram_of_match_table[] = {
+   { .compatible = "brcm,nvram", },
+   {},
+};
+
+static struct platform_driver brcm_nvram_driver = {
+   .probe = brcm_nvram_probe,
+   .driver = {
+   .name = "brcm_nvram",
+   .of_match_table = brcm_nvram_of_match_table,
+   },
+};
+
+static int __init brcm_nvram_init(void)
+{
+   return platform_driver_register(_nvram_driver);
+}
+
+subsys_initcall_sync(brcm_nvram_init);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table);
-- 
2.21.0



[PATCH 08/10] nvmem: rmem: fix undefined reference to memremap

2021-03-30 Thread Srinivas Kandagatla
Fix below error reporte by kernel test robot
rmem.c:(.text+0x14e): undefined reference to memremap
s390x-linux-gnu-ld: rmem.c:(.text+0x1b6): undefined reference to memunmap

Reported-by: kernel test robot 
Fixes: 5a3fa75a4d9c ("nvmem: Add driver to expose reserved memory as nvmem")
Reviewed-by: Nicolas Saenz Julienne 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 642ddc699fd1..dd2019006838 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -272,6 +272,7 @@ config SPRD_EFUSE
 
 config NVMEM_RMEM
tristate "Reserved Memory Based Driver Support"
+   depends on HAS_IOMEM
help
  This driver maps reserved memory into an nvmem device. It might be
  useful to expose information left by firmware in memory.
-- 
2.21.0



[PATCH 03/10] drivers: nvmem: Fix voltage settings for QTI qfprom-efuse

2021-03-30 Thread Srinivas Kandagatla
From: Ravi Kumar Bokka 

QFPROM controller hardware requires 1.8V min for fuse blowing.
So, this change sets the voltage to 1.8V, required to blow the fuse
for qfprom-efuse controller.

To disable fuse blowing, we set the voltage to 0V since this may
be a shared rail and may be able to run at a lower rate when we're
not blowing fuses.

Fixes: 93b4e49f8c86 ("nvmem: qfprom: Add fuse blowing support")
Reported-by: Douglas Anderson 
Suggested-by: Douglas Anderson 
Signed-off-by: Ravi Kumar Bokka 
Reviewed-by: Douglas Anderson 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/qfprom.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 6cace24dfbf7..100d69d8f2e1 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -127,6 +127,16 @@ static void qfprom_disable_fuse_blowing(const struct 
qfprom_priv *priv,
 {
int ret;
 
+   /*
+* This may be a shared rail and may be able to run at a lower rate
+* when we're not blowing fuses.  At the moment, the regulator framework
+* applies voltage constraints even on disabled rails, so remove our
+* constraints and allow the rail to be adjusted by other users.
+*/
+   ret = regulator_set_voltage(priv->vcc, 0, INT_MAX);
+   if (ret)
+   dev_warn(priv->dev, "Failed to set 0 voltage (ignoring)\n");
+
ret = regulator_disable(priv->vcc);
if (ret)
dev_warn(priv->dev, "Failed to disable regulator (ignoring)\n");
@@ -172,6 +182,17 @@ static int qfprom_enable_fuse_blowing(const struct 
qfprom_priv *priv,
goto err_clk_prepared;
}
 
+   /*
+* Hardware requires 1.8V min for fuse blowing; this may be
+* a rail shared do don't specify a max--regulator constraints
+* will handle.
+*/
+   ret = regulator_set_voltage(priv->vcc, 180, INT_MAX);
+   if (ret) {
+   dev_err(priv->dev, "Failed to set 1.8 voltage\n");
+   goto err_clk_rate_set;
+   }
+
ret = regulator_enable(priv->vcc);
if (ret) {
dev_err(priv->dev, "Failed to enable regulator\n");
-- 
2.21.0



[PATCH 04/10] dt-bindings: nvmem: add Broadcom's NVRAM

2021-03-30 Thread Srinivas Kandagatla
From: Rafał Miłecki 

Broadcom's NVRAM structure contains device data and can be accessed
using I/O mapping.

Signed-off-by: Rafał Miłecki 
Reviewed-by: Rob Herring 
Signed-off-by: Srinivas Kandagatla 
---
 .../devicetree/bindings/nvmem/brcm,nvram.yaml | 34 +++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml

diff --git a/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml 
b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml
new file mode 100644
index ..58ff6b0bdb1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/brcm,nvram.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom's NVRAM
+
+description: |
+  Broadcom's NVRAM is a structure containing device specific environment
+  variables. It is used for storing device configuration, booting parameters
+  and calibration data.
+
+  NVRAM can be accessed on Broadcom BCM47xx MIPS and Northstar ARM Cortex-A9
+  devices usiong I/O mapped memory.
+
+maintainers:
+  - Rafał Miłecki 
+
+allOf:
+  - $ref: "nvmem.yaml#"
+
+properties:
+  compatible:
+const: brcm,nvram
+
+unevaluatedProperties: false
+
+examples:
+  - |
+nvram@1eff {
+compatible = "brcm,nvram";
+reg = <0x1eff 0x1>;
+};
-- 
2.21.0



[PATCH 01/10] dt-bindings: nvmem: mediatek: add support for MediaTek mt8192 SoC

2021-03-30 Thread Srinivas Kandagatla
From: Ryan Wu 

This updates dt-binding documentation for MediaTek mt8192

Signed-off-by: Ryan Wu 
Acked-by: Rob Herring 
Signed-off-by: Srinivas Kandagatla 
---
 Documentation/devicetree/bindings/nvmem/mtk-efuse.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt 
b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt
index ef93c3b95424..2f2895b1f06d 100644
--- a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt
+++ b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt
@@ -8,6 +8,7 @@ Required properties:
  "mediatek,mt7623-efuse", "mediatek,efuse": for MT7623
  "mediatek,mt8173-efuse" or "mediatek,efuse": for MT8173
  "mediatek,mt8516-efuse", "mediatek,efuse": for MT8516
+ "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192
 - reg: Should contain registers location and length
 
 = Data cells =
-- 
2.21.0



[PATCH 00/10] nvmem: patches (set 1) for 5.13

2021-03-30 Thread Srinivas Kandagatla
Hi Greg,

Here are some nvmem patches for 5.13 which includes
- adding support to new Broadcom NVRAM, MediaTek mt8192,
 Qualcomm sc7280 nvmem provider
- Add new function to make numbers reading easy
- Update qfprom to support fuse blowing!
- few minor fixes.

Can you please queue them up for 5.13.

thanks for you help,
srini

Colin Ian King (1):
  nvmem: core: Fix unintentional sign extension issue

Douglas Anderson (1):
  nvmem: core: Add functions to make number reading easy

Rafał Miłecki (2):
  dt-bindings: nvmem: add Broadcom's NVRAM
  nvmem: brcm_nvram: new driver exposing Broadcom's NVRAM

Rajendra Nayak (2):
  dt-bindings: nvmem: Add SoC compatible for sc7280
  nvmem: qfprom: Add support for fuse blowing on sc7280

Ravi Kumar Bokka (1):
  drivers: nvmem: Fix voltage settings for QTI qfprom-efuse

Ryan Wu (1):
  dt-bindings: nvmem: mediatek: add support for MediaTek mt8192 SoC

Srinivas Kandagatla (1):
  nvmem: rmem: fix undefined reference to memremap

Zheng Yongjun (1):
  nvmem: convert comma to semicolon

 .../devicetree/bindings/nvmem/brcm,nvram.yaml | 34 +++
 .../devicetree/bindings/nvmem/mtk-efuse.txt   |  1 +
 .../bindings/nvmem/qcom,qfprom.yaml   |  1 +
 drivers/nvmem/Kconfig | 10 ++
 drivers/nvmem/Makefile|  2 +
 drivers/nvmem/brcm_nvram.c| 78 +++
 drivers/nvmem/core.c  | 95 +++
 drivers/nvmem/qcom-spmi-sdam.c|  2 +-
 drivers/nvmem/qfprom.c| 44 +
 drivers/nvmem/snvs_lpgpr.c|  2 +-
 include/linux/nvmem-consumer.h|  4 +
 11 files changed, 271 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml
 create mode 100644 drivers/nvmem/brcm_nvram.c

-- 
2.21.0



[PATCH 02/10] nvmem: convert comma to semicolon

2021-03-30 Thread Srinivas Kandagatla
From: Zheng Yongjun 

Replace a comma between expression statements by a semicolon.

Signed-off-by: Zheng Yongjun 
Reviewed-by: Bjorn Andersson 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/qcom-spmi-sdam.c | 2 +-
 drivers/nvmem/snvs_lpgpr.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
index f6e9f96933ca..4fcb63507ecd 100644
--- a/drivers/nvmem/qcom-spmi-sdam.c
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -141,7 +141,7 @@ static int sdam_probe(struct platform_device *pdev)
sdam->sdam_config.dev = >dev;
sdam->sdam_config.name = "spmi_sdam";
sdam->sdam_config.id = NVMEM_DEVID_AUTO;
-   sdam->sdam_config.owner = THIS_MODULE,
+   sdam->sdam_config.owner = THIS_MODULE;
sdam->sdam_config.stride = 1;
sdam->sdam_config.word_size = 1;
sdam->sdam_config.reg_read = sdam_read;
diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c
index c527d26ca6ac..4692aa985bd6 100644
--- a/drivers/nvmem/snvs_lpgpr.c
+++ b/drivers/nvmem/snvs_lpgpr.c
@@ -123,7 +123,7 @@ static int snvs_lpgpr_probe(struct platform_device *pdev)
cfg->dev = dev;
cfg->stride = 4;
cfg->word_size = 4;
-   cfg->size = dcfg->size,
+   cfg->size = dcfg->size;
cfg->owner = THIS_MODULE;
cfg->reg_read  = snvs_lpgpr_read;
cfg->reg_write = snvs_lpgpr_write;
-- 
2.21.0



Re: [PATCH 1/2] dt-bindings: nvmem: Add SoC compatible for sc7280

2021-03-30 Thread Srinivas Kandagatla




On 25/03/2021 05:44, Rajendra Nayak wrote:

Document SoC compatible for sc7280

Signed-off-by: Rajendra Nayak 
---
  Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
  1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml 
b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 992777c..861b205 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -24,6 +24,7 @@ properties:
- qcom,msm8998-qfprom
- qcom,qcs404-qfprom
- qcom,sc7180-qfprom
+  - qcom,sc7280-qfprom
- qcom,sdm845-qfprom
- const: qcom,qfprom
  



Applied both,
thanks,
srini


Re: [RFC PATCH 1/4] nvmem: core: allow specifying of_node

2021-03-30 Thread Srinivas Kandagatla




On 22/03/2021 18:19, Michael Walle wrote:

Until now, the of_node of the parent device is used. Some devices
provide more than just the nvmem provider. To avoid name space clashes,
add a way to allow specifying the nvmem cells in subnodes. Consider the
following example:

 flash@0 {
 compatible = "jedec,spi-nor";

 partitions {
 compatible = "fixed-partitions";
 #address-cells = <1>;
 #size-cells = <1>;

 partition@0 {
 reg = <0x00 0x01>;
 };
 };

 otp {
 compatible = "mtd-user-otp";


I would have expected this to come up as a proper device, but am not 
100% sure how MTD handles flashes and its partitions.



 #address-cells = <1>;
 #size-cells = <1>;

 serial-number@0 {
 reg = <0x0 0x8>;
 };
 };
 };

There the nvmem provider might be the MTD partition or the OTP region of
the flash.

Add a new config->of_node parameter, which if set, will be used instead
of the parent's of_node.

Signed-off-by: Michael Walle 
---


Patch is fine as it its.
If you plan to take this via mtd tree here is my Ack

Acked-by: Srinivas Kandagatla 


--srini


  drivers/nvmem/core.c   | 4 +++-
  include/linux/nvmem-provider.h | 2 ++
  2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index bca671ff4e54..62d363a399d3 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -789,7 +789,9 @@ struct nvmem_device *nvmem_register(const struct 
nvmem_config *config)
nvmem->reg_write = config->reg_write;
nvmem->keepout = config->keepout;
nvmem->nkeepout = config->nkeepout;
-   if (!config->no_of_node)
+   if (config->of_node)
+   nvmem->dev.of_node = config->of_node;
+   else if (!config->no_of_node)
nvmem->dev.of_node = config->dev->of_node;
  
  	switch (config->id) {

diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index e162b757b6d5..471cb7b9e896 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -57,6 +57,7 @@ struct nvmem_keepout {
   * @type: Type of the nvmem storage
   * @read_only:Device is read-only.
   * @root_only:Device is accessibly to root only.
+ * @of_node:   If given, this will be used instead of the parent's of_node.
   * @no_of_node:   Device should not use the parent's of_node even if it's 
!NULL.
   * @reg_read: Callback to read data.
   * @reg_write:Callback to write data.
@@ -86,6 +87,7 @@ struct nvmem_config {
enum nvmem_type type;
boolread_only;
boolroot_only;
+   struct device_node  *of_node;
boolno_of_node;
nvmem_reg_read_treg_read;
nvmem_reg_write_t   reg_write;



Re: [RFC PATCH 0/4] mtd: core: OTP nvmem provider support

2021-03-30 Thread Srinivas Kandagatla

Hi Michael,

On 22/03/2021 18:19, Michael Walle wrote:

The goal is to fetch a (base) MAC address from the OTP region of a SPI NOR
flash.

This is the first part, where I try to add the nvmem provider support to
the MTD core.

I'm not sure about the device tree bindings. Consider the following two
variants:

(1)
 flash@0 {
 ..

 otp {
 compatible = "mtd-user-otp";
 #address-cells = <1>;
 #size-cells = <1>;

 serial-number@0 {
 reg = <0x0 0x8>;
 };
 };
 };

(2)
 flash@0 {
 ..

 otp {
 compatible = "mtd-user-otp";
 #address-cells = <1>;
 #size-cells = <1>;

some-useful-name {
 compatible = "nvmem-cells";

 serial-number@0 {
 reg = <0x0 0x8>;
 };
};
 };
 };

Both bindings use a subnode "opt[-N]". We cannot have the nvmem cells as
children to the flash node because of the legacy partition binding.

(1) seems to be the form which is used almost everywhere in the kernel.
That is, the nvmem cells are just children of the parent node.

(2) seem to be more natural, because there might also be other properties
inside the otp subnode and might be more future-proof.

At the moment this patch implements (1).




Have you looked at this series[1], are you both trying to do the same thing?

[1] 
https://lore.kernel.org/linux-mtd/20210312062830.20548-2-ansuels...@gmail.com/T/


--srini



Michael Walle (4):
   nvmem: core: allow specifying of_node
   dt-bindings: mtd: add YAML schema for the generic MTD bindings
   dt-bindings: mtd: add OTP bindings
   mtd: core: add OTP nvmem provider support

  .../devicetree/bindings/mtd/common.txt|  16 +-
  .../devicetree/bindings/mtd/mtd.yaml  | 110 +
  drivers/mtd/mtdcore.c | 149 ++
  drivers/nvmem/core.c  |   4 +-
  include/linux/mtd/mtd.h   |   2 +
  include/linux/nvmem-provider.h|   2 +
  6 files changed, 267 insertions(+), 16 deletions(-)
  create mode 100644 Documentation/devicetree/bindings/mtd/mtd.yaml



[PATCH v5 7/9] soundwire: export sdw_compare_devid, sdw_extract_slave_id and sdw_slave_add

2021-03-26 Thread Srinivas Kandagatla
Exporting these three functions makes sense as it can be used by
other controllers like Qualcomm during auto-enumeration!

Reported-by: kernel test robot 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/bus.c   | 4 +++-
 drivers/soundwire/slave.c | 1 +
 include/linux/soundwire/sdw.h | 2 ++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 46885429928a..6d7708964735 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, 
int i)
return NULL;
 }
 
-static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
+int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
 {
if (slave->id.mfg_id != id.mfg_id ||
slave->id.part_id != id.part_id ||
@@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, 
struct sdw_slave_id id)
 
return 0;
 }
+EXPORT_SYMBOL(sdw_compare_devid);
 
 /* called with bus_lock held */
 static int sdw_get_device_num(struct sdw_slave *slave)
@@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
"SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, 
unique_id 0x%x, version 0x%x\n",
id->class_id, id->mfg_id, id->part_id, id->unique_id, 
id->sdw_version);
 }
+EXPORT_SYMBOL(sdw_extract_slave_id);
 
 static int sdw_program_device_num(struct sdw_bus *bus)
 {
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index 180f38bd003b..92850e150d36 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus,
 
return ret;
 }
+EXPORT_SYMBOL(sdw_slave_add);
 
 #if IS_ENABLED(CONFIG_ACPI)
 
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 2f52d6609076..f9003ba056ba 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -1011,5 +1011,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 
value);
 int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
 int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
 int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
+int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
+void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id 
*id);
 
 #endif /* __SOUNDWIRE_H */
-- 
2.21.0



[PATCH v5 4/9] soundwire: qcom: start the clock during initialization

2021-03-26 Thread Srinivas Kandagatla
Start the clock during initialization, doing this explicitly
will add more clarity when we are adding clock stop feature.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 43ec22a5e332..2bcb4362f0e0 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -47,6 +47,8 @@
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
 #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
+#define SWRM_MCP_BUS_CTRL  0x1044
+#define SWRM_MCP_BUS_CLK_START BIT(1)
 #define SWRM_MCP_CFG_ADDR  0x1048
 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK  GENMASK(21, 17)
 #define SWRM_DEF_CMD_NO_PINGS  0x1f
@@ -343,6 +345,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32p_replace_bits(, SWRM_DEF_CMD_NO_PINGS, 
SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
+   ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
/* Configure number of retries of a read/write cmd */
if (ctrl->version > 0x01050001) {
/* Only for versions >= 1.5.1 */
-- 
2.21.0



[PATCH v5 9/9] soundwire: qcom: wait for enumeration to be complete in probe

2021-03-26 Thread Srinivas Kandagatla
Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index c6c923329b15..706d44200a36 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -123,6 +123,7 @@ struct qcom_swrm_ctrl {
struct regmap *regmap;
void __iomem *mmio;
struct completion broadcast;
+   struct completion enumeration;
struct work_struct slave_work;
/* Port alloc/free lock */
struct mutex port_lock;
@@ -417,6 +418,7 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus)
}
}
 
+   complete(>enumeration);
return 0;
 }
 
@@ -1155,6 +1157,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
dev_set_drvdata(>dev, ctrl);
mutex_init(>port_lock);
init_completion(>broadcast);
+   init_completion(>enumeration);
 
ctrl->bus.ops = _swrm_ops;
ctrl->bus.port_ops = _swrm_port_ops;
@@ -1201,6 +1204,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
}
 
qcom_swrm_init(ctrl);
+   wait_for_completion_timeout(>enumeration,
+   msecs_to_jiffies(TIMEOUT_MS));
ret = qcom_swrm_register_dais(ctrl);
if (ret)
goto err_master_add;
-- 
2.21.0



[PATCH v5 6/9] soundwire: qcom: add support to new interrupts

2021-03-26 Thread Srinivas Kandagatla
Add support to new interrupts which includes reporting some of the
error interrupts and adding support to SLAVE pending interrupt!

This patch also changes the interrupt handler behaviour on handling
any pending interrupts by checking it before returning out of irq handler.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 161 ---
 1 file changed, 135 insertions(+), 26 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 0cbd611fb8c6..6a563fb52444 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -28,10 +28,21 @@
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK
GENMASK(9, 5)
 #define SWRM_INTERRUPT_STATUS  0x200
 #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
+#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ   BIT(0)
 #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED   BIT(1)
 #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
+#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOWBIT(5)
+#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6)
 #define SWRM_INTERRUPT_STATUS_CMD_ERRORBIT(7)
+#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION  BIT(8)
+#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCHBIT(9)
 #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED  BIT(10)
+#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13)
+#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2  BIT(14)
+#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP   BIT(16)
+#define SWRM_INTERRUPT_MAX 17
 #define SWRM_INTERRUPT_MASK_ADDR   0x204
 #define SWRM_INTERRUPT_CLEAR   0x208
 #define SWRM_INTERRUPT_CPU_EN  0x210
@@ -58,6 +69,7 @@
 #define SWRM_MCP_STATUS_BANK_NUM_MASK  BIT(0)
 #define SWRM_MCP_SLV_STATUS0x1090
 #define SWRM_MCP_SLV_STATUS_MASK   GENMASK(1, 0)
+#define SWRM_MCP_SLV_STATUS_SZ 2
 #define SWRM_DP_PORT_CTRL_BANK(n, m)   (0x1124 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL_1(n)(0x112C + 0x100 * (n - 1))
@@ -123,6 +135,7 @@ struct qcom_swrm_ctrl {
int rows_index;
unsigned long dout_port_mask;
unsigned long din_port_mask;
+   u32 intr_mask;
u8 rcmd_id;
u8 wcmd_id;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -304,6 +317,25 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl 
*swrm,
return SDW_CMD_IGNORED;
 }
 
+static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
+{
+   u32 val, status;
+   int dev_num;
+
+   ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+
+   for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) {
+   status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
+
+   if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
+   ctrl->status[dev_num] = status;
+   return dev_num;
+   }
+   }
+
+   return -EINVAL;
+}
+
 static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
 {
u32 val;
@@ -322,36 +354,112 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
 
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
-   struct qcom_swrm_ctrl *ctrl = dev_id;
-   u32 sts, value;
+   struct qcom_swrm_ctrl *swrm = dev_id;
+   u32 value, intr_sts, intr_sts_masked;
+   u32 i;
+   u8 devnum = 0;
+   int ret = IRQ_HANDLED;
 
-   ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, );
+   swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, _sts);
+   intr_sts_masked = intr_sts & swrm->intr_mask;
 
-   if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) {
-   ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, );
-   dev_err_ratelimited(ctrl->dev,
-   "CMD error, fifo status 0x%x\n",
-value);
-   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
-   }
-
-   if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
-   sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) {
-   qcom_swrm_get_device_status(ctrl);
-   sdw_handle_slave_status(>bus, ctrl->s

[PATCH v5 8/9] soundwire: qcom: add auto enumeration support

2021-03-26 Thread Srinivas Kandagatla
Qualcomm SoundWire controller supports Auto Enumeration of the
devices within the IP. This patch enables support for this feature.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 86 +---
 1 file changed, 81 insertions(+), 5 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6a563fb52444..c6c923329b15 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -57,6 +57,8 @@
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
 #define SWRM_RD_FIFO_CMD_ID_MASK   GENMASK(11, 8)
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
+#define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m)  (0x530 + 0x8 * (m))
+#define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m)  (0x534 + 0x8 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
 #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
@@ -143,6 +145,7 @@ struct qcom_swrm_ctrl {
enum sdw_slave_status status[SDW_MAX_DEVICES];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
+   u32 slave_status;
 };
 
 struct qcom_swrm_data {
@@ -342,6 +345,7 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
int i;
 
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+   ctrl->slave_status = val;
 
for (i = 0; i < SDW_MAX_DEVICES; i++) {
u32 s;
@@ -352,10 +356,74 @@ static void qcom_swrm_get_device_status(struct 
qcom_swrm_ctrl *ctrl)
}
 }
 
+static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus,
+   struct sdw_slave *slave, int devnum)
+{
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   u32 status;
+
+   ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, );
+   status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ));
+   status &= SWRM_MCP_SLV_STATUS_MASK;
+
+   if (status == SDW_SLAVE_ATTACHED) {
+   if (slave)
+   slave->dev_num = devnum;
+   mutex_lock(>bus_lock);
+   set_bit(devnum, bus->assigned);
+   mutex_unlock(>bus_lock);
+   }
+}
+
+static int qcom_swrm_enumerate(struct sdw_bus *bus)
+{
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   struct sdw_slave *slave, *_s;
+   struct sdw_slave_id id;
+   u32 val1, val2;
+   bool found;
+   u64 addr;
+   int i;
+   char *buf1 = (char *), *buf2 = (char *)
+
+   for (i = 1; i <= SDW_MAX_DEVICES; i++) {
+   /*SCP_Devid5 - Devid 4*/
+   ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), );
+
+   /*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/
+   ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), );
+
+   if (!val1 && !val2)
+   break;
+
+   addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) |
+   ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) |
+   ((u64)buf1[0] << 40);
+
+   sdw_extract_slave_id(bus, addr, );
+   found = false;
+   /* Now compare with entries */
+   list_for_each_entry_safe(slave, _s, >slaves, node) {
+   if (sdw_compare_devid(slave, id) == 0) {
+   qcom_swrm_set_slave_dev_num(bus, slave, i);
+   found = true;
+   break;
+   }
+   }
+
+   if (!found) {
+   qcom_swrm_set_slave_dev_num(bus, NULL, i);
+   sdw_slave_add(bus, , NULL);
+   }
+   }
+
+   return 0;
+}
+
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
struct qcom_swrm_ctrl *swrm = dev_id;
-   u32 value, intr_sts, intr_sts_masked;
+   u32 value, intr_sts, intr_sts_masked, slave_status;
u32 i;
u8 devnum = 0;
int ret = IRQ_HANDLED;
@@ -384,8 +452,15 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void 
*dev_id)
case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
dev_err_ratelimited(swrm->dev, "%s: SWR new 
slave attached\n",
__func__);
-   qcom_swrm_get_device_status(swrm);
-   sdw_handle_slave_status(>bus, 
swrm->status);
+   swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, 
_status);
+   if (swrm->slave_status 

[PATCH v5 5/9] soundwire: qcom: update register read/write routine

2021-03-26 Thread Srinivas Kandagatla
In the existing code every soundwire register read and register write
are kinda blocked. Each of these are using a special command id that
generates interrupt after it successfully finishes. This is really
overhead, limiting and not really necessary unless we are doing
something special.

We can simply read/write the fifo that should also give exactly
what we need! This will also allow to read/write registers in
interrupt context, which was not possible with the special
command approach.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
 21: 130 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
 21: 3 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

This has significantly not only reduced interrupting CPU during enumeration
but also during streaming!

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 178 ++-
 1 file changed, 99 insertions(+), 79 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 2bcb4362f0e0..0cbd611fb8c6 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -38,11 +38,13 @@
 #define SWRM_CMD_FIFO_WR_CMD   0x300
 #define SWRM_CMD_FIFO_RD_CMD   0x304
 #define SWRM_CMD_FIFO_CMD  0x308
+#define SWRM_CMD_FIFO_FLUSH0x1
 #define SWRM_CMD_FIFO_STATUS   0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
+#define SWRM_RD_FIFO_CMD_ID_MASK   GENMASK(11, 8)
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)   (0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
@@ -78,13 +80,16 @@
 #define SWRM_SPECIAL_CMD_ID0xF
 #define MAX_FREQ_NUM   1
 #define TIMEOUT_MS (2 * HZ)
-#define QCOM_SWRM_MAX_RD_LEN   0xf
+#define QCOM_SWRM_MAX_RD_LEN   0x1
 #define QCOM_SDW_MAX_PORTS 14
 #define DEFAULT_CLK_FREQ   960
 #define SWRM_MAX_DAIS  0xF
 #define SWR_INVALID_PARAM 0xFF
 #define SWR_HSTOP_MAX_VAL 0xF
 #define SWR_HSTART_MIN_VAL 0x0
+#define SWR_BROADCAST_CMD_ID0x0F
+#define SWR_MAX_CMD_ID 14
+#define MAX_FIFO_RD_RETRY 3
 
 struct qcom_swrm_port_config {
u8 si;
@@ -103,10 +108,8 @@ struct qcom_swrm_ctrl {
struct device *dev;
struct regmap *regmap;
void __iomem *mmio;
-   struct completion *comp;
+   struct completion broadcast;
struct work_struct slave_work;
-   /* read/write lock */
-   spinlock_t comp_lock;
/* Port alloc/free lock */
struct mutex port_lock;
struct clk *hclk;
@@ -120,6 +123,8 @@ struct qcom_swrm_ctrl {
int rows_index;
unsigned long dout_port_mask;
unsigned long din_port_mask;
+   u8 rcmd_id;
+   u8 wcmd_id;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES];
@@ -198,77 +203,105 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl 
*ctrl, int reg,
return SDW_CMD_OK;
 }
 
-static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
-u8 dev_addr, u16 reg_addr)
+static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
+  u8 dev_addr, u16 reg_addr)
 {
-   DECLARE_COMPLETION_ONSTACK(comp);
-   unsigned long flags;
u32 val;
-   int ret;
-
-   spin_lock_irqsave(>comp_lock, flags);
-   ctrl->comp = 
-   spin_unlock_irqrestore(>comp_lock, flags);
-   val = SWRM_REG_VAL_PACK(cmd_data, dev_addr,
-   SWRM_SPECIAL_CMD_ID, reg_addr);
-   ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val);
-   if (ret)
-   goto err;
-
-   ret = wait_for_completion_timeout(ctrl->comp,
- msecs_to_jiffies(TIMEOUT_MS));
+   u8 id = *cmd_id;
 
-   if (!ret)
-   ret = SDW_CMD_IGNORED;
-   else
-   ret = SDW_CMD_OK;
-err:
-   spin_lock_irqsave(>comp_lock, flags);
-   ctrl->comp = NULL;
-   spin_unlock_irqrestore(>comp_lock, flags);
+   if (id != SWR_BROADCAST_CMD_ID) {
+   if (id < SWR_MAX_CMD_ID)
+   id += 1;
+   else
+   id = 0;
+

[PATCH v5 3/9] soundwire: qcom: set continue execution flag for ignored commands

2021-03-26 Thread Srinivas Kandagatla
version 1.5.1 and higher IPs of this controller required to set
continue execution on ignored command flag. This patch sets this flag.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index d05e41f68658..43ec22a5e332 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -40,6 +40,7 @@
 #define SWRM_CMD_FIFO_CMD  0x308
 #define SWRM_CMD_FIFO_STATUS   0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
+#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE   BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES 0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
 #define SWRM_ENUMERATOR_CFG_ADDR   0x500
@@ -343,7 +344,15 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
/* Configure number of retries of a read/write cmd */
-   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES);
+   if (ctrl->version > 0x01050001) {
+   /* Only for versions >= 1.5.1 */
+   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+   SWRM_RD_WR_CMD_RETRIES |
+   SWRM_CONTINUE_EXEC_ON_CMD_IGNORE);
+   } else {
+   ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+   SWRM_RD_WR_CMD_RETRIES);
+   }
 
/* Set IRQ to PULSE */
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
-- 
2.21.0



[PATCH v5 2/9] soundwire: qcom: add support to missing transport params

2021-03-26 Thread Srinivas Kandagatla
Some of the transport parameters derived from device tree
are not fully parsed by the driver.

This patch adds support to parse those missing parameters.

Signed-off-by: Srinivas Kandagatla 
Reviewed-by: Pierre-Louis Bossart 
---
 drivers/soundwire/qcom.c | 107 ++-
 1 file changed, 95 insertions(+), 12 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 39222b04a2e0..d05e41f68658 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -54,7 +54,13 @@
 #define SWRM_MCP_SLV_STATUS0x1090
 #define SWRM_MCP_SLV_STATUS_MASK   GENMASK(1, 0)
 #define SWRM_DP_PORT_CTRL_BANK(n, m)   (0x1124 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_BLOCK_CTRL_1(n)(0x112C + 0x100 * (n - 1))
+#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_HCTRL_BANK(n, m)  (0x1134 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DIN_DPn_PCM_PORT_CTRL(n)  (0x1054 + 0x100 * (n - 1))
+
 #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
@@ -73,12 +79,20 @@
 #define QCOM_SDW_MAX_PORTS 14
 #define DEFAULT_CLK_FREQ   960
 #define SWRM_MAX_DAIS  0xF
+#define SWR_INVALID_PARAM 0xFF
+#define SWR_HSTOP_MAX_VAL 0xF
+#define SWR_HSTART_MIN_VAL 0x0
 
 struct qcom_swrm_port_config {
u8 si;
u8 off1;
u8 off2;
u8 bp_mode;
+   u8 hstart;
+   u8 hstop;
+   u8 word_length;
+   u8 blk_group_count;
+   u8 lane_control;
 };
 
 struct qcom_swrm_ctrl {
@@ -396,8 +410,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
 struct sdw_port_params *p_params,
 unsigned int bank)
 {
-   /* TBD */
-   return 0;
+   struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+
+   return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num),
+  p_params->bps - 1);
+
 }
 
 static int qcom_swrm_transport_params(struct sdw_bus *bus,
@@ -405,20 +422,45 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
  enum sdw_reg_bank bank)
 {
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+   struct qcom_swrm_port_config *pcfg;
u32 value;
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
int ret;
 
-   value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
-   value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
-   value |= params->sample_interval - 1;
+   pcfg = >pconfig[params->port_num - 1];
+
+   value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
+   value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
+   value |= pcfg->si;
 
ret = ctrl->reg_write(ctrl, reg, value);
 
-   if (!ret && params->blk_pkg_mode) {
-   reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+   if (pcfg->lane_control != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
+   value = pcfg->lane_control;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
+
+   if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
+   value = pcfg->blk_group_count;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
+
+   if (pcfg->hstart != SWR_INVALID_PARAM
+   && pcfg->hstop != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+   value = (pcfg->hstop << 4) | pcfg->hstart;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   } else {
+   reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+   value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
+   ret = ctrl->reg_write(ctrl, reg, value);
+   }
 
-   ret = ctrl->reg_write(ctrl, reg, 1);
+   if (pcfg->bp_mode != SWR_INVALID_PARAM) {
+   reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+   ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
 
return ret;
@@ -468,10 +510,13 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
list_for_each_entry(p_rt, _rt->port_list, port_node) {
pcfg = >pconfig[p_rt->num - 1];
p_rt->transport_par

[PATCH v5 0/9] soundwire: qcom: various improvements

2021-03-26 Thread Srinivas Kandagatla
Thanks for reviewing v4 of this patchset!

During testing SoundWire controller on SM8250 MTP, we found
few issues like all the interrupts are not handled,
all transport parameters are not read from device tree.
Patch to add Auto Enumeration supported by the controller
is also part of this series.

Other major issue was register read/writes which was interrupt based
was an overhead and puts lot of limitation on context it can be used from.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
21: 130 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
21: 3 0 0 0 0 0 0 0 GICv3 234 Edge  soundwire

So this patchset add various improvements to the existing driver
to address above issues.

Tested it on SM8250 MTP with 2x WSA881x speakers, HeadPhones on
WCD938x via lpass-rx-macro and Analog MICs via lpass-tx-macro.
Also tested on DragonBoard DB845c with 2xWSA881x speakers.

Changes since v4:
- exported sdw_slave_add as kernel test robot reported error

Srinivas Kandagatla (9):
  dt-bindings: soundwire: qcom: clarify data port bus parameters
  soundwire: qcom: add support to missing transport params
  soundwire: qcom: set continue execution flag for ignored commands
  soundwire: qcom: start the clock during initialization
  soundwire: qcom: update register read/write routine
  soundwire: qcom: add support to new interrupts
  soundwire: export sdw_compare_devid, sdw_extract_slave_id and
sdw_slave_add
  soundwire: qcom: add auto enumeration support
  soundwire: qcom: wait for enumeration to be complete in probe

 .../bindings/soundwire/qcom,sdw.txt   |  20 +
 drivers/soundwire/bus.c   |   4 +-
 drivers/soundwire/qcom.c  | 529 ++
 drivers/soundwire/slave.c |   1 +
 include/linux/soundwire/sdw.h |   2 +
 5 files changed, 443 insertions(+), 113 deletions(-)

-- 
2.21.0



[PATCH v5 1/9] dt-bindings: soundwire: qcom: clarify data port bus parameters

2021-03-26 Thread Srinivas Kandagatla
Some of the parameters for data ports are not applicable or not implemented
in IP. So mark them as invalid/not applicable in DT so that controller is
aware of this.

Add comment to these bindings to provide more clarity on the values!

Signed-off-by: Srinivas Kandagatla 
Acked-by: Rob Herring 
Reviewed-by: Pierre-Louis Bossart 
---
 .../bindings/soundwire/qcom,sdw.txt   | 20 +++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt 
b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
index b104be131235..b93a2b3e029d 100644
--- a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
+++ b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
@@ -54,6 +54,8 @@ board specific bus parameters.
Value type: 
Definition: should specify payload transport window offset1 of each
data port. Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-offset2:
@@ -61,6 +63,8 @@ board specific bus parameters.
Value type: 
Definition: should specify payload transport window offset2 of each
data port. Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-sinterval-low:
@@ -69,12 +73,16 @@ board specific bus parameters.
Definition: should be sample interval low of each data port.
Out ports followed by In ports. Used for Sample Interval
calculation.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-word-length:
Usage: optional
Value type: 
Definition: should be size of payload channel sample.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-block-pack-mode:
@@ -84,6 +92,8 @@ board specific bus parameters.
0 to indicate Blocks are per Channel
1 to indicate Blocks are per Port.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-block-group-count:
@@ -92,6 +102,8 @@ board specific bus parameters.
Definition: should be in range 1 to 4 to indicate how many sample
intervals are combined into a payload.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-lane-control:
@@ -100,6 +112,8 @@ board specific bus parameters.
Definition: should be in range 0 to 7 to identify which data lane
the data port uses.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-hstart:
@@ -109,6 +123,8 @@ board specific bus parameters.
SoundWire Frame, i.e. left edge of the Transport sub-frame
for each port. Values between 0 and 15 are valid.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,ports-hstop:
@@ -118,6 +134,8 @@ board specific bus parameters.
SoundWire Frame, i.e. the right edge of the Transport
sub-frame for each port. Values between 0 and 15 are valid.
Out ports followed by In ports.
+   Value of 0xFF indicates that this option is not implemented
+   or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
 
 - qcom,dports-type:
@@ -128,6 +146,8 @@ board specific bus parameters.
1 for simple ports

Re: [PATCH] drivers: nvmem: Fix voltage settings for QTI qfprom-efuse

2021-03-25 Thread Srinivas Kandagatla




On 25/03/2021 07:15, Rajendra Nayak wrote:




Looks right to me.  Assuming that this works.

Reviewed-by: Douglas Anderson 


Srini, any plans to queue this up for merge?


https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/drivers/nvmem?id=4d57a383a437e63909ccfe15b8a116f7ff5bb673

This is already in next queued up for next merge.

thanks,
srini


Re: [PATCH v3 3/7] ASoC: codecs: wcd938x: add basic driver

2021-03-22 Thread Srinivas Kandagatla




On 19/03/2021 15:59, Pierre-Louis Bossart wrote:



On 3/19/21 4:29 AM, Srinivas Kandagatla wrote:

This patch adds basic SoundWire codec driver to support for
WCD938X TX and RX devices.


It took me a while to figure out that you are adding support for a codec 
that has 2 Slave interfaces internally, one for TX and one for RX dais.


Each of the interfaces will appear as a separate Linux device, even 
though they are physically in the same hardware component.


That perfectly legit from a SoundWire standpoint, but I wonder how you 
are going to handle pm_runtime and regmap access if the two parts are 
joined at the hip for imp-def register access (described in the cover 
letter as "Even though this device has two SoundWire devices, only tx 
device has access to main codec Control/Status Registers!").


I was clearly unable to figure out how regmap/gpios/regulator were 
handled between the two TX and TX parts.




tx regmap is shared between both the devices.
Regulators are also handled in common code for tx and rx device.

I added more detailed reply in cover letter reply.




See more below.

diff --git a/sound/soc/codecs/wcd938x-sdw.c 
b/sound/soc/codecs/wcd938x-sdw.c

new file mode 100644
index ..ca29793b0972
--- /dev/null
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0


GPL-2.0-only for consistency with the other additions below?



Sure will fix that!


+static int wcd9380_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+    struct device *dev = >dev;
+    struct wcd938x_sdw_priv *wcd;
+    const char *dir = "rx";
+    int ret;
+
+    wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+    if (!wcd)
+    return -ENOMEM;
+
+    of_property_read_string(dev->of_node, "direction", );
+    if (!strcmp(dir, "tx"))
+    wcd->is_tx = true;
+    else
+    wcd->is_tx = false;
+
+


extra line

+    ret = of_property_read_variable_u32_array(dev->of_node, 
"qcom,port-mapping",

+  wcd->port_map,
+  WCD938X_MAX_TX_SWR_PORTS,
+  WCD938X_MAX_SWR_PORTS);
+    if (ret)
+    dev_info(dev, "Static Port mapping not specified\n");
+
+    wcd->sdev = pdev;
+    dev_set_drvdata(dev, wcd);
+    ret = wcd938x_init(wcd);
+    if (ret)
+    return ret;
+
+    pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+    SDW_SCP_INT1_BUS_CLASH |
+    SDW_SCP_INT1_PARITY;
+    pdev->prop.lane_control_support = true;
+    if (wcd->is_tx) {
+    pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
+    pdev->prop.src_dpn_prop = wcd938x_dpn_prop;
+    wcd->ch_info = _sdw_tx_ch_info[0];
+    pdev->prop.wake_capable = true;
+    } else {
+    pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
+    pdev->prop.sink_dpn_prop = wcd938x_dpn_prop;
+    wcd->ch_info = _sdw_rx_ch_info[0];
+    }
+
+    if (wcd->is_tx)
+    return wcd938x_register_component(wcd, dev, _tx_dai);
+    else
+    return wcd938x_register_component(wcd, dev, _rx_dai);
+
+}
+
+static const struct sdw_device_id wcd9380_slave_id[] = {
+    SDW_SLAVE_ENTRY(0x0217, 0x10d, 0),


does this mean you cannot determine the functionality of the device by 
looking at the devId registers?



No, we can not, they have same device id.

I would have expected each interface to have a different part ID to show 
that they are different...such tricks would not work in the ACPI world 
at the moment, the expectation was really that different part numbers 
are unique enough to know what to expect.




+    {},
+};
+MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id);
+
+static struct sdw_driver wcd9380_codec_driver = {
+    .probe    = wcd9380_probe,
+    .ops = _slave_ops,
+    .id_table = wcd9380_slave_id,
+    .driver = {
+    .name    = "wcd9380-codec",
+    }
+};
+module_sdw_driver(wcd9380_codec_driver);


[...]

+static bool wcd938x_readable_register(struct device *dev, unsigned 
int reg)

+{
+    bool ret;
+
+    ret = wcd938x_readonly_register(dev, reg);
+    if (!ret)
+    return wcd938x_rdwr_register(dev, reg);
+
+    return ret;
+}
+
+static bool wcd938x_writeable_register(struct device *dev, unsigned 
int reg)

+{
+    return wcd938x_rdwr_register(dev, reg);
+}
+
+static bool wcd938x_volatile_register(struct device *dev, unsigned 
int reg)

+{
+    if (reg <= WCD938X_BASE_ADDRESS)
+    return 0;
+
+    if (reg == WCD938X_DIGITAL_SWR_TX_CLK_RATE)
+    return true;
+
+    if (wcd938x_readonly_register(dev, reg))
+    return true;
+
+    return false;
+}


this part is quite confusing, you mentioned that only the TX interface 
has access to registers, but here you seem to expose regmap registers 
for both TX and RX?


No, this regmap is only for tx.

Am happy to prefix them 

Re: [PATCH v3 0/7] ASoC: codecs: add wcd938x support

2021-03-22 Thread Srinivas Kandagatla

Many thanks Pierre for reviewing the patches,

On 19/03/2021 16:09, Pierre-Louis Bossart wrote:



On 3/19/21 4:29 AM, Srinivas Kandagatla wrote:

This patchset adds support for Qualcomm WCD938X codec.

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices, RX and
TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs and MBHC.

Even though this device has two SoundWire devices, only tx device has
access to main codec Control/Status Registers!


That part is a new concept we haven't seen so far with SoundWire 
support, and I added a number of comments in the patches.


It would really help if you could add more explanations on how 
regmap/pm_runtime/gpios/regulators/interrupts are supposed to work with 
such a functional split. Thanks!



codec regmap for Control and status registers are only possible via TX 
Soundwire device as per h.w wiring.
In the existing code we take care of this in common code (wcd938x.c) 
shared between TX and RX devices.


pm runtime is also handled in the common code, Ex. resume on rx dev will 
make sure that tx dev is resumed first, and suspend on rx is nop.


I have tested basic pm runtime auto-suspend cases with this.

same with reset gpios/regulators and regulators.

SDW Interrupts are also via tx device.






This patchset along with other SoundWire patches on the list
have been tested on SM8250 MTP device.

Am planning to send support for MBHC once this driver gets accepted!

Thanks,
srini

Many thanks for reviewing v2.


Changes since v2:
- fixed dt_binding_check error


Srinivas Kandagatla (7):
   ASoC: dt-bindings: wcd938x: add bindings for wcd938x
   ASoC: codecs: wcd-clsh: add new version support
   ASoC: codecs: wcd938x: add basic driver
   ASoC: codecs: wcd938x: add basic controls
   ASoC: codecs: wcd938x: add playback dapm widgets
   ASoC: codecs: wcd938x: add capture dapm widgets
   ASoC: codecs: wcd938x: add audio routing

  .../bindings/sound/qcom,wcd938x.yaml  |  165 +
  sound/soc/codecs/Kconfig  |    9 +
  sound/soc/codecs/Makefile |    2 +
  sound/soc/codecs/wcd-clsh-v2.c    |  350 +-
  sound/soc/codecs/wcd-clsh-v2.h    |   16 +
  sound/soc/codecs/wcd938x-sdw.c    |  291 ++
  sound/soc/codecs/wcd938x.c    | 3623 +
  sound/soc/codecs/wcd938x.h    |  676 +++
  8 files changed, 5122 insertions(+), 10 deletions(-)
  create mode 100644 
Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml

  create mode 100644 sound/soc/codecs/wcd938x-sdw.c
  create mode 100644 sound/soc/codecs/wcd938x.c
  create mode 100644 sound/soc/codecs/wcd938x.h



Re: [PATCH v3 2/7] ASoC: codecs: wcd-clsh: add new version support

2021-03-22 Thread Srinivas Kandagatla




On 19/03/2021 15:23, Pierre-Louis Bossart wrote:


+static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component 
*component,

+  int mode)
+{
+    u8 val = 0;


initialization not needed.


I agree, will remove this in next spin.


+
+    switch (mode) {
+    case CLS_H_NORMAL:
+    val = 0x00;
+    break;
+    case CLS_AB:
+    case CLS_H_ULP:
+    val = 0x0C;
+    break;
+    case CLS_AB_HIFI:
+    case CLS_H_HIFI:
+    val = 0x08;
+    break;
+    case CLS_H_LP:
+    case CLS_H_LOHIFI:
+    case CLS_AB_LP:
+    case CLS_AB_LOHIFI:
+    val = 0x04;
+    break;
+    default:
+    dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode);
+    return;
+    };
+
+    snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, 
val);

+}
+
+


extra line


will remove this in next spin.


+void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode)
+{
+    struct snd_soc_component *comp = ctrl->comp;
+
+    if (ctrl->codec_version >= WCD937X)
+    wcd_clsh_v3_set_hph_mode(comp, mode);
+    else
+    wcd_clsh_v2_set_hph_mode(comp, mode);
+
+}
+
  static void wcd_clsh_set_flyback_current(struct snd_soc_component 
*comp,

   int mode)
  {
@@ -289,6 +388,130 @@ static void 
wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp,

  WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H);
  }
+static void wcd_clsh_v3_set_buck_regulator_mode(struct 
snd_soc_component *component,

+    int mode)
+{
+    snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES,
+    0x02, 0x00);
+}
+
+static inline void wcd_clsh_v3_set_flyback_mode(struct 
snd_soc_component *component,

+    int mode)
+{
+    if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+    mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) {
+    snd_soc_component_update_bits(component,
+    WCD9XXX_ANA_RX_SUPPLIES,
+    0x04, 0x04);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_FLYBACK_VNEG_CTRL_4,
+    0xF0, 0x80);
+    } else {
+    snd_soc_component_update_bits(component,
+    WCD9XXX_ANA_RX_SUPPLIES,
+    0x04, 0x00); /* set to Default */
+    snd_soc_component_update_bits(component,
+    WCD9XXX_FLYBACK_VNEG_CTRL_4,
+    0xF0, 0x70);
+    }
+}
+
+static inline void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component 
*component,

+ int mode, bool enable)
+{
+    if (enable) {
+    snd_soc_component_update_bits(component,
+    WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
+    0xE0, 0xA0);
+    /* 100usec delay is needed as per HW requirement */
+    usleep_range(100, 110);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_CLASSH_MODE_3,
+    0x02, 0x02);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_CLASSH_MODE_2,
+    0xFF, 0x1C);
+    if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) {
+    snd_soc_component_update_bits(component,
+    WCD9XXX_HPH_NEW_INT_PA_MISC2,
+    0x20, 0x20);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_RX_BIAS_HPH_LOWPOWER,
+    0xF0, 0xC0);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_HPH_PA_CTL1,
+    0x0E, 0x02);
+    }
+    } else {
+    snd_soc_component_update_bits(component,
+    WCD9XXX_HPH_NEW_INT_PA_MISC2,
+    0x20, 0x00);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_RX_BIAS_HPH_LOWPOWER,
+    0xF0, 0x80);
+    snd_soc_component_update_bits(component,
+    WCD9XXX_HPH_PA_CTL1,
+    0x0E, 0x06);
+    }
+}


do you need the inline for the two functions above?

yes, these are totally unnecessary.

--srini





[PATCH v3 7/7] ASoC: codecs: wcd938x: add audio routing

2021-03-19 Thread Srinivas Kandagatla
This patch adds audio routing for both playback and capture.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 97 ++
 1 file changed, 97 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 31e3cf729568..0f801920ebac 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -3153,6 +3153,99 @@ static const struct snd_soc_dapm_widget 
wcd938x_rx_dapm_widgets[] = {
 
 };
 
+static const struct snd_soc_dapm_route wcd938x_rx_audio_map[] = {
+   {"IN1_HPHL", NULL, "VDD_BUCK"},
+   {"IN1_HPHL", NULL, "CLS_H_PORT"},
+
+   {"RX1", NULL, "IN1_HPHL"},
+   {"RX1", NULL, "RXCLK"},
+   {"RDAC1", NULL, "RX1"},
+   {"HPHL_RDAC", "Switch", "RDAC1"},
+   {"HPHL PGA", NULL, "HPHL_RDAC"},
+   {"HPHL", NULL, "HPHL PGA"},
+
+   {"IN2_HPHR", NULL, "VDD_BUCK"},
+   {"IN2_HPHR", NULL, "CLS_H_PORT"},
+   {"RX2", NULL, "IN2_HPHR"},
+   {"RDAC2", NULL, "RX2"},
+   {"RX2", NULL, "RXCLK"},
+   {"HPHR_RDAC", "Switch", "RDAC2"},
+   {"HPHR PGA", NULL, "HPHR_RDAC"},
+   {"HPHR", NULL, "HPHR PGA"},
+
+   {"IN3_AUX", NULL, "VDD_BUCK"},
+   {"IN3_AUX", NULL, "CLS_H_PORT"},
+   {"RX3", NULL, "IN3_AUX"},
+   {"RDAC4", NULL, "RX3"},
+   {"RX3", NULL, "RXCLK"},
+   {"AUX_RDAC", "Switch", "RDAC4"},
+   {"AUX PGA", NULL, "AUX_RDAC"},
+   {"AUX", NULL, "AUX PGA"},
+
+   {"RDAC3_MUX", "RX3", "RX3"},
+   {"RDAC3_MUX", "RX1", "RX1"},
+   {"RDAC3", NULL, "RDAC3_MUX"},
+   {"EAR_RDAC", "Switch", "RDAC3"},
+   {"EAR PGA", NULL, "EAR_RDAC"},
+   {"EAR", NULL, "EAR PGA"},
+};
+
+static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
+   {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+   {"ADC1_MIXER", "Switch", "ADC1 REQ"},
+   {"ADC1 REQ", NULL, "ADC1"},
+   {"ADC1", NULL, "AMIC1"},
+
+   {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+   {"ADC2_MIXER", "Switch", "ADC2 REQ"},
+   {"ADC2 REQ", NULL, "ADC2"},
+   {"ADC2", NULL, "HDR12 MUX"},
+   {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"},
+   {"HDR12 MUX", "HDR12", "AMIC1"},
+   {"ADC2 MUX", "INP3", "AMIC3"},
+   {"ADC2 MUX", "INP2", "AMIC2"},
+
+   {"ADC3_OUTPUT", NULL, "ADC3_MIXER"},
+   {"ADC3_MIXER", "Switch", "ADC3 REQ"},
+   {"ADC3 REQ", NULL, "ADC3"},
+   {"ADC3", NULL, "HDR34 MUX"},
+   {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"},
+   {"HDR34 MUX", "HDR34", "AMIC5"},
+   {"ADC3 MUX", "INP4", "AMIC4"},
+   {"ADC3 MUX", "INP6", "AMIC6"},
+
+   {"ADC4_OUTPUT", NULL, "ADC4_MIXER"},
+   {"ADC4_MIXER", "Switch", "ADC4 REQ"},
+   {"ADC4 REQ", NULL, "ADC4"},
+   {"ADC4", NULL, "ADC4 MUX"},
+   {"ADC4 MUX", "INP5", "AMIC5"},
+   {"ADC4 MUX", "INP7", "AMIC7"},
+
+   {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+   {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+   {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+   {"DMIC2_MIXER", "Switch", "DMIC2"},
+
+   {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"},
+   {"DMIC3_MIXER", "Switch", "DMIC3"},
+
+   {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"},
+   {"DMIC4_MIXER", "Switch", "DMIC4"},
+
+   {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"},
+   {"DMIC5_MIXER", "Switch", "DMIC5"},
+
+   {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"},
+   {"DMIC6_MIXER", "Switch", "DMIC6"},
+
+   {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"},
+   {"DMIC7_MIXER", "Switch", "DMIC7"},
+
+   {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"},
+   {"DMIC8_MIXER", "Switch", "DMIC8"},
+};
+
 static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
 {
/* min micbias voltage is 1V and maximum is 2.85V */
@@ -3332,6 +3425,8 @@ static const struct snd_soc_component_driver 
soc_codec_dev_wcd938x_sdw_rx = {
.num_controls = ARRAY_SIZE(wcd938x_rx_snd_controls),
.dapm_widgets = wcd938x_rx_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wcd938x_rx_dapm_widgets),
+   .dapm_routes = wcd938x_rx_audio_map,
+   .num_dapm_routes = ARRAY_SIZE(wcd938x_rx_audio_map),
 };
 
 static const struct snd_soc_component_driver soc_codec_dev_wcd938x_sdw_tx = {
@@ -3341,6 +3436,8 @@ static const struct snd_soc_component_driver 
soc_codec_dev_wcd938x_sdw_tx = {
.num_controls = ARRAY_SIZE(wcd938x_snd_controls),
.dapm_widgets = wcd938x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets),
+   .dapm_routes = wcd938x_audio_map,
+   .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map),
 };
 
 static void wcd938x_dt_parse_micbias_info(struct device *dev, struct 
wcd938x_priv *wcd)
-- 
2.21.0



[PATCH v3 5/7] ASoC: codecs: wcd938x: add playback dapm widgets

2021-03-19 Thread Srinivas Kandagatla
This patch adds required dapm widgets for playback.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 700 +
 1 file changed, 700 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 9b5dda775a17..59e41296a489 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1321,6 +1321,601 @@ static int wcd938x_connect_port(struct 
snd_soc_component *component, u8 ch_id, u
enable);
 }
 
+static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX0_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX1_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX2_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, WCD938X_AUX_AUXPA,
+ WCD938X_AUXPA_CLK_EN_MASK, 1);
+   break;
+   case SND_SOC_DAPM_POST_PMD:
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VNEG_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VPOS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 0);
+   break;
+   }
+   return 0;
+}
+
+static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+   struct snd_kcontrol *kcontrol,
+   int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_DIG_CLK_CTL,
+   WCD938X_RXD0_CLK_EN_MASK, 0x01);
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_HPH_GAIN_CTL,
+   WCD938X_HPHL_RX_EN_MASK, 1);
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_RDAC_CLK_CTL1,
+   WCD938X_CHOP_CLK_EN_MASK, 0);
+   break;
+   case SND_SOC_DAPM_POST_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+   WCD938X_HPH_RES_DIV_MASK, 0x02);
+   if (wcd938x->comp1_enable) {
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_COMP_CTL_0,
+   WCD938X_HPHL_COMP_EN_MASK, 1);
+   /* 5msec compander delay as per HW requirement */
+   if (!wcd938x->comp2_enable || 
(snd_soc_component_read(component,
+
WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01))
+   usleep_range(5000, 5010);
+   snd_soc_component_write_field(component, 
WCD938X_HPH_NEW_INT_HPH_TIMER1,
+ WCD938X_AUTOCHOP_TIMER_EN, 0);
+   } else {
+   snd_soc_component_write_field(component,
+   WCD938X_DIG

[PATCH v3 3/7] ASoC: codecs: wcd938x: add basic driver

2021-03-19 Thread Srinivas Kandagatla
This patch adds basic SoundWire codec driver to support for
WCD938X TX and RX devices.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/Kconfig   |9 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/wcd938x-sdw.c |  291 ++
 sound/soc/codecs/wcd938x.c | 1615 
 sound/soc/codecs/wcd938x.h |  676 +
 5 files changed, 2593 insertions(+)
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4ab34bca71aa..17fe1f690d22 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -231,6 +231,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
+   imply SND_SOC_WCD938X
imply SND_SOC_LPASS_RX_MACRO
imply SND_SOC_LPASS_TX_MACRO
imply SND_SOC_WL1273
@@ -1521,6 +1522,14 @@ config SND_SOC_WCD934X
  The WCD9340/9341 is a audio codec IC Integrated in
  Qualcomm SoCs like SDM845.
 
+config SND_SOC_WCD938X
+   tristate "WCD9380/WCD9385 Codec"
+   depends on SOUNDWIRE
+   select REGMAP_SOUNDWIRE
+   help
+ The WCD9380/9385 is a audio codec IC Integrated in
+ Qualcomm SoCs like SM8250.
+
 config SND_SOC_WL1273
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index edff5c5b92d3..c7dbe84d939e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -249,6 +249,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
 snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
+snd-soc-wcd938x-objs := wcd938x.o wcd938x-sdw.o wcd-clsh-v2.o wcd938x-sdw.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -568,6 +569,7 @@ obj-$(CONFIG_SND_SOC_UDA134X)   += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WCD9335)  += snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)  += snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD938X)  += snd-soc-wcd938x.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM0010)   += snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
new file mode 100644
index ..ca29793b0972
--- /dev/null
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021, Linaro Limited
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "wcd938x.h"
+
+#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+   SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+   SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+SNDRV_PCM_RATE_176400)
+#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+   SNDRV_PCM_FMTBIT_S24_LE)
+#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
+};
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)),
+   WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC7, WCD938X_

[PATCH v3 6/7] ASoC: codecs: wcd938x: add capture dapm widgets

2021-03-19 Thread Srinivas Kandagatla
This patch adds required dapm widgets for capture path.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 796 +
 1 file changed, 796 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 59e41296a489..31e3cf729568 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -150,6 +150,16 @@ enum {
NUM_CODEC_DAIS,
 };
 
+static u8 tx_mode_bit[] = {
+   [ADC_MODE_INVALID] = 0x00,
+   [ADC_MODE_HIFI] = 0x01,
+   [ADC_MODE_LO_HIF] = 0x02,
+   [ADC_MODE_NORMAL] = 0x04,
+   [ADC_MODE_LP] = 0x08,
+   [ADC_MODE_ULP1] = 0x10,
+   [ADC_MODE_ULP2] = 0x20,
+};
+
 struct wcd938x_priv {
struct device *dev;
struct regmap *regmap;
@@ -1229,6 +1239,70 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = {
.irq_drv_data = NULL,
 };
 
+static int wcd938x_swr_slv_get_current_bank(struct wcd938x_sdw_priv *wcd)
+{
+   int bank;
+
+   bank  = sdw_read(wcd->sdev, SDW_SCP_CTRL);
+
+   return ((bank & 0x40) ? 1 : 0);
+}
+
+static int wcd938x_get_clk_rate(int mode)
+{
+   int rate;
+
+   switch (mode) {
+   case ADC_MODE_ULP2:
+   rate = SWR_CLK_RATE_0P6MHZ;
+   break;
+   case ADC_MODE_ULP1:
+   rate = SWR_CLK_RATE_1P2MHZ;
+   break;
+   case ADC_MODE_LP:
+   rate = SWR_CLK_RATE_4P8MHZ;
+   break;
+   case ADC_MODE_NORMAL:
+   case ADC_MODE_LO_HIF:
+   case ADC_MODE_HIFI:
+   case ADC_MODE_INVALID:
+   default:
+   rate = SWR_CLK_RATE_9P6MHZ;
+   break;
+   }
+
+   return rate;
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int 
rate, int bank)
+{
+   u8 mask = (bank ? 0xF0 : 0x0F);
+   u8 val = 0;
+
+   switch (rate) {
+   case SWR_CLK_RATE_0P6MHZ:
+   val = (bank ? 0x60 : 0x06);
+   break;
+   case SWR_CLK_RATE_1P2MHZ:
+   val = (bank ? 0x50 : 0x05);
+   break;
+   case SWR_CLK_RATE_2P4MHZ:
+   val = (bank ? 0x30 : 0x03);
+   break;
+   case SWR_CLK_RATE_4P8MHZ:
+   val = (bank ? 0x10 : 0x01);
+   break;
+   case SWR_CLK_RATE_9P6MHZ:
+   default:
+   val = 0x00;
+   break;
+   }
+   snd_soc_component_update_bits(component, 
WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+ mask, val);
+
+   return 0;
+}
+
 int wcd938x_io_init(struct wcd938x_sdw_priv *wcd)
 {
struct regmap *rm = wcd->wcd938x->regmap;
@@ -1916,6 +1990,463 @@ static int wcd938x_codec_enable_ear_pa(struct 
snd_soc_dapm_widget *w,
return 0;
 }
 
+static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol,
+int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   u16 dmic_clk_reg, dmic_clk_en_reg;
+   u8 dmic_sel_mask, dmic_clk_mask;
+
+   switch (w->shift) {
+   case 0:
+   case 1:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL;
+   dmic_clk_mask = WCD938X_DMIC1_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK;
+   break;
+   case 2:
+   case 3:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL;
+   dmic_clk_mask = WCD938X_DMIC2_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK;
+   break;
+   case 4:
+   case 5:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL;
+   dmic_clk_mask = WCD938X_DMIC3_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK;
+   break;
+   case 6:
+   case 7:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL;
+   dmic_clk_mask = WCD938X_DMIC4_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK;
+   break;
+   default:
+   dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+   __func__);
+   return -EINVAL;
+   };
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_AMIC_CTL,
+   dmic_sel_mask,
+   WCD938X_AMIC1_IN_SEL_DMIC);
+   /* 250us sleep as per HW requirement */
+   usleep_range(250, 260);
+   /* S

[PATCH v3 4/7] ASoC: codecs: wcd938x: add basic controls

2021-03-19 Thread Srinivas Kandagatla
This patch adds basic controls found in wcd938x codec.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 415 +
 1 file changed, 415 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 9e8d588e2235..9b5dda775a17 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -66,6 +66,15 @@
 #define WCD938X_MBHC_MOISTURE_RREF  R_24_KOHM
 #define WCD_MBHC_HS_V_MAX   1600
 
+#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
+{  .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+   .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+   .tlv.p = (tlv_array), \
+   .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+   .put = wcd938x_ear_pa_put_gain, \
+   .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+
 enum {
WCD9380 = 0,
WCD9385 = 5,
@@ -187,6 +196,9 @@ enum {
 };
 
 static struct wcd938x_priv *g_wcd938x;
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
 
 static const struct reg_default wcd938x_defaults[] = {
{WCD938X_ANA_PAGE_REGISTER,0x00},
@@ -1275,6 +1287,380 @@ int wcd938x_io_init(struct wcd938x_sdw_priv *wcd)
 
 }
 
+static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+   struct sdw_port_config *port_config,
+   u32 mstr_port_num,
+   u8 enable)
+{
+   u8 ch_mask, port_num;
+
+   port_num = ch_info->port_num;
+   ch_mask = ch_info->ch_mask;
+
+   port_config->num = port_num;
+
+   if (enable)
+   port_config->ch_mask |= ch_mask;
+   else
+   port_config->ch_mask &= ~ch_mask;
+
+   return 0;
+}
+
+static int wcd938x_connect_port(struct snd_soc_component *component, u8 ch_id, 
u8 enable)
+{
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   u8 port_num, mstr_port_num;
+
+   port_num = wcd->ch_info[ch_id].port_num;
+   mstr_port_num = wcd->port_map[port_num - 1];
+
+   return wcd938x_sdw_connect_port(>ch_info[ch_id],
+   >port_config[port_num],
+   mstr_port_num,
+   enable);
+}
+
+static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   ucontrol->value.integer.value[0] = wcd938x->tx_mode[path];
+
+   return 0;
+}
+
+static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   ucontrol->value.integer.value[0] = wcd938x->hph_mode;
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   s

[PATCH v3 2/7] ASoC: codecs: wcd-clsh: add new version support

2021-03-19 Thread Srinivas Kandagatla
>From WCD937X Class H controller has changed significantly, so add support
to this new version for WCD937X and WCD938X Codecs.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd-clsh-v2.c | 350 -
 sound/soc/codecs/wcd-clsh-v2.h |  16 ++
 2 files changed, 356 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 817d8259758c..60e2e784d190 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -88,6 +88,19 @@ struct wcd_clsh_ctrl {
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
 
+#define WCD9XXX_BASE_ADDRESS   0x3000
+#define WCD9XXX_ANA_RX_SUPPLIES
(WCD9XXX_BASE_ADDRESS+0x008)
+#define WCD9XXX_ANA_HPH
(WCD9XXX_BASE_ADDRESS+0x009)
+#define WCD9XXX_CLASSH_MODE_2  
(WCD9XXX_BASE_ADDRESS+0x098)
+#define WCD9XXX_CLASSH_MODE_3  
(WCD9XXX_BASE_ADDRESS+0x099)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_1
(WCD9XXX_BASE_ADDRESS+0x0A5)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_4
(WCD9XXX_BASE_ADDRESS+0x0A8)
+#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 
(WCD9XXX_BASE_ADDRESS+0x0AF)
+#define WCD9XXX_RX_BIAS_HPH_LOWPOWER   
(WCD9XXX_BASE_ADDRESS+0x0BF)
+#define WCD9XXX_V3_RX_BIAS_FLYB_BUFF   
(WCD9XXX_BASE_ADDRESS+0x0C7)
+#define WCD9XXX_HPH_PA_CTL1
(WCD9XXX_BASE_ADDRESS+0x0D1)
+#define WCD9XXX_HPH_NEW_INT_PA_MISC2   
(WCD9XXX_BASE_ADDRESS+0x138)
+
 #define CLSH_REQ_ENABLEtrue
 #define CLSH_REQ_DISABLE   false
 #define WCD_USLEEP_RANGE   50
@@ -137,6 +150,20 @@ static inline void wcd_clsh_set_buck_mode(struct 
snd_soc_component *comp,
WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
 }
 
+static inline void wcd_clsh_v3_set_buck_mode(struct snd_soc_component 
*component,
+ int mode)
+{
+   if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+   mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x08); /* set to HIFI */
+   else
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x00); /* set to default */
+}
+
 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
 int mode)
 {
@@ -170,6 +197,36 @@ static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
usleep_range(500, 500 + WCD_USLEEP_RANGE);
 }
 
+static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component,
+  struct wcd_clsh_ctrl *ctrl,
+  int mode,
+  bool enable)
+{
+   /* enable/disable buck */
+   if ((enable && (++ctrl->buck_users == 1)) ||
+  (!enable && (--ctrl->buck_users == 0))) {
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   (1 << 7), (enable << 7));
+   /*
+* 500us sleep is required after buck enable/disable
+* as per HW requirement
+*/
+   usleep_range(500, 510);
+   if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
+   mode == CLS_H_HIFI || mode == CLS_H_LP)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_3,
+   0x02, 0x00);
+
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_2,
+   0xFF, 0x3A);
+   /* 500usec delay is needed as per HW requirement */
+   usleep_range(500, 500 + WCD_USLEEP_RANGE);
+   }
+}
+
 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
  int mode,
  bool enable)
@@ -219,8 +276,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl 
*ctrl, int mode)
val);
 }
 
-static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp,
- int mode)
+static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp,  int mode)
 {
int val = 0, gain = 0, res_val;
int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
@@ -264,6 +320,49 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component 
*comp,

[PATCH v3 1/7] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-03-19 Thread Srinivas Kandagatla
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire device RX and
TX respectively, supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs, MBHC.

Signed-off-by: Srinivas Kandagatla 
---
 .../bindings/sound/qcom,wcd938x.yaml  | 165 ++
 1 file changed, 165 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
new file mode 100644
index ..fe47e483d4b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd938x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm WCD9380/WCD9385 Audio Codec
+
+maintainers:
+  - Srinivas Kandagatla 
+
+description: |
+  Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices.
+
+properties:
+  compatible:
+const: sdw20217010d00
+
+  reg:
+maxItems: 1
+
+  reset-gpios:
+description: GPIO spec for reset line to use
+maxItems: 1
+
+  direction:
+oneOf:
+  - const: rx
+  - const: tx
+
+  vdd-buck-supply:
+description: A reference to the 1.8V buck supply
+
+  vdd-rxtx-supply:
+description: A reference to the 1.8V rx supply
+
+  vdd-io-supply:
+description: A reference to the 1.8V I/O supply
+
+  qcom,micbias1-microvolt:
+description: micbias1 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias2-microvolt:
+description: micbias2 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias3-microvolt:
+description: micbias3 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias4-microvolt:
+description: micbias4 voltage
+minimum: 180
+maximum: 285
+
+  qcom,mbhc-hphl-switch:
+description: Indicates that HPHL switch type is normally closed
+type: boolean
+
+  qcom,mbhc-ground-switch:
+description: Indicates that Headset Ground switch type is normally closed
+type: boolean
+
+  qcom,mbhc-button0-vthreshold-microvolt:
+description: Voltage threshold value headset button0
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button1-vthreshold-microvolt:
+description: Voltage threshold value headset button1
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button2-vthreshold-microvolt:
+description: Voltage threshold value headset button2
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button3-vthreshold-microvolt:
+description: Voltage threshold value headset button3
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button4-vthreshold-microvolt:
+description: Voltage threshold value headset button4
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button5-vthreshold-microvolt:
+description: Voltage threshold value headset button5
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button6-vthreshold-microvolt:
+description: Voltage threshold value headset button6
+minimum: 0
+maximum: 50
+
+  qcom,mbhc-button7-vthreshold-microvolt:
+description: Voltage threshold value headset button7
+minimum: 0
+maximum: 50
+
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+$ref: /schemas/types.yaml#/definitions/uint32-array
+minItems: 4
+maxItems: 5
+
+  '#sound-dai-cells':
+const: 1
+
+required:
+  - compatible
+  - reg
+  - reset-gpios
+  - qcom,micbias1-microvolt
+  - qcom,micbias2-microvolt
+  - qcom,micbias3-microvolt
+  - qcom,micbias4-microvolt
+  - qcom,port-mapping
+  - qcom,mbhc-hphl-switch
+  - qcom,mbhc-ground-switch
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+
+codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+reset-gpios = < 32 0>;
+direction = "tx";
+#sound-dai-cells = <1>;
+qcom,micbias1-microvolt = <180>;
+qcom,micbias2-microvolt = <180>;
+qcom,micbias3-microvolt = <180>;
+qcom,micbias4-microvolt = <180>;
+qcom,mbhc-hphl-switch;
+qcom,mbhc-ground-switch;
+qcom,mbhc-button0-vthreshold-microvolt = <75000>;
+qcom,mbhc-button1-vthreshold-microvolt = <15>;
+qcom,mbhc-button2-vthreshold-microvolt = <237000>;
+qcom,mbhc-button3-vthreshold-microvolt = <500

[PATCH v3 0/7] ASoC: codecs: add wcd938x support

2021-03-19 Thread Srinivas Kandagatla
This patchset adds support for Qualcomm WCD938X codec.

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices, RX and
TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs and MBHC.

Even though this device has two SoundWire devices, only tx device has
access to main codec Control/Status Registers!

This patchset along with other SoundWire patches on the list
have been tested on SM8250 MTP device.

Am planning to send support for MBHC once this driver gets accepted!

Thanks,
srini

Many thanks for reviewing v2.


Changes since v2:
- fixed dt_binding_check error


Srinivas Kandagatla (7):
  ASoC: dt-bindings: wcd938x: add bindings for wcd938x
  ASoC: codecs: wcd-clsh: add new version support
  ASoC: codecs: wcd938x: add basic driver
  ASoC: codecs: wcd938x: add basic controls
  ASoC: codecs: wcd938x: add playback dapm widgets
  ASoC: codecs: wcd938x: add capture dapm widgets
  ASoC: codecs: wcd938x: add audio routing

 .../bindings/sound/qcom,wcd938x.yaml  |  165 +
 sound/soc/codecs/Kconfig  |9 +
 sound/soc/codecs/Makefile |2 +
 sound/soc/codecs/wcd-clsh-v2.c|  350 +-
 sound/soc/codecs/wcd-clsh-v2.h|   16 +
 sound/soc/codecs/wcd938x-sdw.c|  291 ++
 sound/soc/codecs/wcd938x.c| 3623 +
 sound/soc/codecs/wcd938x.h|  676 +++
 8 files changed, 5122 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

-- 
2.21.0



Re: [PATCH] dt-bindings: Drop type references on common properties

2021-03-17 Thread Srinivas Kandagatla




On 16/03/2021 19:48, Rob Herring wrote:

Users of common properties shouldn't have a type definition as the
common schemas already have one. Drop all the unnecessary type
references in the tree.

A meta-schema update to catch these is pending.

Cc: Nicolas Saenz Julienne
Cc: Maxime Ripard
Cc: Linus Walleij
Cc: Bartosz Golaszewski
Cc: Bjorn Andersson
Cc: Krzysztof Kozlowski
Cc: Marc Kleine-Budde
Cc: "David S. Miller"
Cc: Jakub Kicinski
Cc: Srinivas Kandagatla
Cc: Ohad Ben-Cohen
Cc: Mark Brown
Cc: Cheng-Yi Chiang
Cc: Benson Leung
Cc: Zhang Rui
Cc: Daniel Lezcano
Cc: Greg Kroah-Hartman
Cc: Stefan Wahren
Cc: Masahiro Yamada
Cc: Odelu Kukatla
Cc: Alex Elder
Cc: Suman Anna
Cc: Kuninori Morimoto
Cc: Dmitry Baryshkov
Cc:linux-g...@vger.kernel.org
Cc:linux...@vger.kernel.org
Cc:linux-...@vger.kernel.org
Cc:net...@vger.kernel.org
Cc:linux-remotep...@vger.kernel.org
Cc:alsa-de...@alsa-project.org
Cc:linux-...@vger.kernel.org
Signed-off-by: Rob Herring
---
  .../bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml   | 5 +
  Documentation/devicetree/bindings/arm/cpus.yaml  | 2 --
  .../bindings/display/allwinner,sun4i-a10-tcon.yaml   | 1 -
  .../devicetree/bindings/gpio/socionext,uniphier-gpio.yaml| 3 +--
  .../devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml  | 1 -
  .../devicetree/bindings/interconnect/qcom,rpmh.yaml  | 1 -
  .../bindings/memory-controllers/nvidia,tegra210-emc.yaml | 2 +-
  Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml   | 1 -
  Documentation/devicetree/bindings/net/qcom,ipa.yaml  | 1 -
  Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml  | 2 --


For nvmem parts,

Reviewed-by: Srinivas Kandagatla 

--srini


Re: [PATCH] dt-bindings: nvmem: use base meta-schema for consumer schema

2021-03-17 Thread Srinivas Kandagatla




On 16/03/2021 19:51, Rob Herring wrote:

Common consumer schemas need to use the base.yaml meta-schema because
they need to define different constraints (e.g. the type) from what
users of the common schema need to define (e.g. how many entries).

Cc: Srinivas Kandagatla 
Signed-off-by: Rob Herring 
---


Reviewed-by: Srinivas Kandagatla 

--srini



  Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml 
b/Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml
index 828e4a1ece41..b1da238c8bcb 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml
@@ -2,7 +2,7 @@
  %YAML 1.2
  ---
  $id: http://devicetree.org/schemas/nvmem/nvmem-consumer.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
+$schema: http://devicetree.org/meta-schemas/base.yaml#
  
  title: NVMEM (Non Volatile Memory) Consumer Device Tree Bindings
  



[PATCH v2 6/7] ASoC: codecs: wcd938x: add capture dapm widgets

2021-03-16 Thread Srinivas Kandagatla
This patch adds required dapm widgets for capture path.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 796 +
 1 file changed, 796 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 59e41296a489..31e3cf729568 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -150,6 +150,16 @@ enum {
NUM_CODEC_DAIS,
 };
 
+static u8 tx_mode_bit[] = {
+   [ADC_MODE_INVALID] = 0x00,
+   [ADC_MODE_HIFI] = 0x01,
+   [ADC_MODE_LO_HIF] = 0x02,
+   [ADC_MODE_NORMAL] = 0x04,
+   [ADC_MODE_LP] = 0x08,
+   [ADC_MODE_ULP1] = 0x10,
+   [ADC_MODE_ULP2] = 0x20,
+};
+
 struct wcd938x_priv {
struct device *dev;
struct regmap *regmap;
@@ -1229,6 +1239,70 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = {
.irq_drv_data = NULL,
 };
 
+static int wcd938x_swr_slv_get_current_bank(struct wcd938x_sdw_priv *wcd)
+{
+   int bank;
+
+   bank  = sdw_read(wcd->sdev, SDW_SCP_CTRL);
+
+   return ((bank & 0x40) ? 1 : 0);
+}
+
+static int wcd938x_get_clk_rate(int mode)
+{
+   int rate;
+
+   switch (mode) {
+   case ADC_MODE_ULP2:
+   rate = SWR_CLK_RATE_0P6MHZ;
+   break;
+   case ADC_MODE_ULP1:
+   rate = SWR_CLK_RATE_1P2MHZ;
+   break;
+   case ADC_MODE_LP:
+   rate = SWR_CLK_RATE_4P8MHZ;
+   break;
+   case ADC_MODE_NORMAL:
+   case ADC_MODE_LO_HIF:
+   case ADC_MODE_HIFI:
+   case ADC_MODE_INVALID:
+   default:
+   rate = SWR_CLK_RATE_9P6MHZ;
+   break;
+   }
+
+   return rate;
+}
+
+static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int 
rate, int bank)
+{
+   u8 mask = (bank ? 0xF0 : 0x0F);
+   u8 val = 0;
+
+   switch (rate) {
+   case SWR_CLK_RATE_0P6MHZ:
+   val = (bank ? 0x60 : 0x06);
+   break;
+   case SWR_CLK_RATE_1P2MHZ:
+   val = (bank ? 0x50 : 0x05);
+   break;
+   case SWR_CLK_RATE_2P4MHZ:
+   val = (bank ? 0x30 : 0x03);
+   break;
+   case SWR_CLK_RATE_4P8MHZ:
+   val = (bank ? 0x10 : 0x01);
+   break;
+   case SWR_CLK_RATE_9P6MHZ:
+   default:
+   val = 0x00;
+   break;
+   }
+   snd_soc_component_update_bits(component, 
WCD938X_DIGITAL_SWR_TX_CLK_RATE,
+ mask, val);
+
+   return 0;
+}
+
 int wcd938x_io_init(struct wcd938x_sdw_priv *wcd)
 {
struct regmap *rm = wcd->wcd938x->regmap;
@@ -1916,6 +1990,463 @@ static int wcd938x_codec_enable_ear_pa(struct 
snd_soc_dapm_widget *w,
return 0;
 }
 
+static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol,
+int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   u16 dmic_clk_reg, dmic_clk_en_reg;
+   u8 dmic_sel_mask, dmic_clk_mask;
+
+   switch (w->shift) {
+   case 0:
+   case 1:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL;
+   dmic_clk_mask = WCD938X_DMIC1_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK;
+   break;
+   case 2:
+   case 3:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL;
+   dmic_clk_mask = WCD938X_DMIC2_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK;
+   break;
+   case 4:
+   case 5:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL;
+   dmic_clk_mask = WCD938X_DMIC3_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK;
+   break;
+   case 6:
+   case 7:
+   dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4;
+   dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL;
+   dmic_clk_mask = WCD938X_DMIC4_RATE_MASK;
+   dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK;
+   break;
+   default:
+   dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+   __func__);
+   return -EINVAL;
+   };
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_AMIC_CTL,
+   dmic_sel_mask,
+   WCD938X_AMIC1_IN_SEL_DMIC);
+   /* 250us sleep as per HW requirement */
+   usleep_range(250, 260);
+   /* S

[PATCH v2 7/7] ASoC: codecs: wcd938x: add audio routing

2021-03-16 Thread Srinivas Kandagatla
This patch adds audio routing for both playback and capture.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 97 ++
 1 file changed, 97 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 31e3cf729568..0f801920ebac 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -3153,6 +3153,99 @@ static const struct snd_soc_dapm_widget 
wcd938x_rx_dapm_widgets[] = {
 
 };
 
+static const struct snd_soc_dapm_route wcd938x_rx_audio_map[] = {
+   {"IN1_HPHL", NULL, "VDD_BUCK"},
+   {"IN1_HPHL", NULL, "CLS_H_PORT"},
+
+   {"RX1", NULL, "IN1_HPHL"},
+   {"RX1", NULL, "RXCLK"},
+   {"RDAC1", NULL, "RX1"},
+   {"HPHL_RDAC", "Switch", "RDAC1"},
+   {"HPHL PGA", NULL, "HPHL_RDAC"},
+   {"HPHL", NULL, "HPHL PGA"},
+
+   {"IN2_HPHR", NULL, "VDD_BUCK"},
+   {"IN2_HPHR", NULL, "CLS_H_PORT"},
+   {"RX2", NULL, "IN2_HPHR"},
+   {"RDAC2", NULL, "RX2"},
+   {"RX2", NULL, "RXCLK"},
+   {"HPHR_RDAC", "Switch", "RDAC2"},
+   {"HPHR PGA", NULL, "HPHR_RDAC"},
+   {"HPHR", NULL, "HPHR PGA"},
+
+   {"IN3_AUX", NULL, "VDD_BUCK"},
+   {"IN3_AUX", NULL, "CLS_H_PORT"},
+   {"RX3", NULL, "IN3_AUX"},
+   {"RDAC4", NULL, "RX3"},
+   {"RX3", NULL, "RXCLK"},
+   {"AUX_RDAC", "Switch", "RDAC4"},
+   {"AUX PGA", NULL, "AUX_RDAC"},
+   {"AUX", NULL, "AUX PGA"},
+
+   {"RDAC3_MUX", "RX3", "RX3"},
+   {"RDAC3_MUX", "RX1", "RX1"},
+   {"RDAC3", NULL, "RDAC3_MUX"},
+   {"EAR_RDAC", "Switch", "RDAC3"},
+   {"EAR PGA", NULL, "EAR_RDAC"},
+   {"EAR", NULL, "EAR PGA"},
+};
+
+static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
+   {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+   {"ADC1_MIXER", "Switch", "ADC1 REQ"},
+   {"ADC1 REQ", NULL, "ADC1"},
+   {"ADC1", NULL, "AMIC1"},
+
+   {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+   {"ADC2_MIXER", "Switch", "ADC2 REQ"},
+   {"ADC2 REQ", NULL, "ADC2"},
+   {"ADC2", NULL, "HDR12 MUX"},
+   {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"},
+   {"HDR12 MUX", "HDR12", "AMIC1"},
+   {"ADC2 MUX", "INP3", "AMIC3"},
+   {"ADC2 MUX", "INP2", "AMIC2"},
+
+   {"ADC3_OUTPUT", NULL, "ADC3_MIXER"},
+   {"ADC3_MIXER", "Switch", "ADC3 REQ"},
+   {"ADC3 REQ", NULL, "ADC3"},
+   {"ADC3", NULL, "HDR34 MUX"},
+   {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"},
+   {"HDR34 MUX", "HDR34", "AMIC5"},
+   {"ADC3 MUX", "INP4", "AMIC4"},
+   {"ADC3 MUX", "INP6", "AMIC6"},
+
+   {"ADC4_OUTPUT", NULL, "ADC4_MIXER"},
+   {"ADC4_MIXER", "Switch", "ADC4 REQ"},
+   {"ADC4 REQ", NULL, "ADC4"},
+   {"ADC4", NULL, "ADC4 MUX"},
+   {"ADC4 MUX", "INP5", "AMIC5"},
+   {"ADC4 MUX", "INP7", "AMIC7"},
+
+   {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+   {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+   {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+   {"DMIC2_MIXER", "Switch", "DMIC2"},
+
+   {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"},
+   {"DMIC3_MIXER", "Switch", "DMIC3"},
+
+   {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"},
+   {"DMIC4_MIXER", "Switch", "DMIC4"},
+
+   {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"},
+   {"DMIC5_MIXER", "Switch", "DMIC5"},
+
+   {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"},
+   {"DMIC6_MIXER", "Switch", "DMIC6"},
+
+   {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"},
+   {"DMIC7_MIXER", "Switch", "DMIC7"},
+
+   {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"},
+   {"DMIC8_MIXER", "Switch", "DMIC8"},
+};
+
 static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
 {
/* min micbias voltage is 1V and maximum is 2.85V */
@@ -3332,6 +3425,8 @@ static const struct snd_soc_component_driver 
soc_codec_dev_wcd938x_sdw_rx = {
.num_controls = ARRAY_SIZE(wcd938x_rx_snd_controls),
.dapm_widgets = wcd938x_rx_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wcd938x_rx_dapm_widgets),
+   .dapm_routes = wcd938x_rx_audio_map,
+   .num_dapm_routes = ARRAY_SIZE(wcd938x_rx_audio_map),
 };
 
 static const struct snd_soc_component_driver soc_codec_dev_wcd938x_sdw_tx = {
@@ -3341,6 +3436,8 @@ static const struct snd_soc_component_driver 
soc_codec_dev_wcd938x_sdw_tx = {
.num_controls = ARRAY_SIZE(wcd938x_snd_controls),
.dapm_widgets = wcd938x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets),
+   .dapm_routes = wcd938x_audio_map,
+   .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map),
 };
 
 static void wcd938x_dt_parse_micbias_info(struct device *dev, struct 
wcd938x_priv *wcd)
-- 
2.21.0



[PATCH v2 5/7] ASoC: codecs: wcd938x: add playback dapm widgets

2021-03-16 Thread Srinivas Kandagatla
This patch adds required dapm widgets for playback.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 700 +
 1 file changed, 700 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 9b5dda775a17..59e41296a489 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1321,6 +1321,601 @@ static int wcd938x_connect_port(struct 
snd_soc_component *component, u8 ch_id, u
enable);
 }
 
+static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 1);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX0_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX1_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_RX2_CTL,
+   WCD938X_DEM_DITHER_ENABLE_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 1);
+   snd_soc_component_write_field(component, WCD938X_AUX_AUXPA,
+ WCD938X_AUXPA_CLK_EN_MASK, 1);
+   break;
+   case SND_SOC_DAPM_POST_PMD:
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VNEG_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_VPOS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_ANA_RX_SUPPLIES,
+   WCD938X_RX_BIAS_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 0);
+   snd_soc_component_write_field(component, 
WCD938X_DIGITAL_CDC_ANA_CLK_CTL,
+   WCD938X_ANA_RX_CLK_EN_MASK, 0);
+   break;
+   }
+   return 0;
+}
+
+static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+   struct snd_kcontrol *kcontrol,
+   int event)
+{
+   struct snd_soc_component *component = 
snd_soc_dapm_to_component(w->dapm);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_DIG_CLK_CTL,
+   WCD938X_RXD0_CLK_EN_MASK, 0x01);
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_HPH_GAIN_CTL,
+   WCD938X_HPHL_RX_EN_MASK, 1);
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_RDAC_CLK_CTL1,
+   WCD938X_CHOP_CLK_EN_MASK, 0);
+   break;
+   case SND_SOC_DAPM_POST_PMU:
+   snd_soc_component_write_field(component,
+   WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+   WCD938X_HPH_RES_DIV_MASK, 0x02);
+   if (wcd938x->comp1_enable) {
+   snd_soc_component_write_field(component,
+   WCD938X_DIGITAL_CDC_COMP_CTL_0,
+   WCD938X_HPHL_COMP_EN_MASK, 1);
+   /* 5msec compander delay as per HW requirement */
+   if (!wcd938x->comp2_enable || 
(snd_soc_component_read(component,
+
WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01))
+   usleep_range(5000, 5010);
+   snd_soc_component_write_field(component, 
WCD938X_HPH_NEW_INT_HPH_TIMER1,
+ WCD938X_AUTOCHOP_TIMER_EN, 0);
+   } else {
+   snd_soc_component_write_field(component,
+   WCD938X_DIG

[PATCH v2 3/7] ASoC: codecs: wcd938x: add basic driver

2021-03-16 Thread Srinivas Kandagatla
This patch adds basic SoundWire codec driver to support for
WCD938X TX and RX devices.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/Kconfig   |9 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/wcd938x-sdw.c |  291 ++
 sound/soc/codecs/wcd938x.c | 1615 
 sound/soc/codecs/wcd938x.h |  676 +
 5 files changed, 2593 insertions(+)
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6ce74c99a305..1c35cb21b61e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -230,6 +230,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
+   imply SND_SOC_WCD938X
imply SND_SOC_LPASS_RX_MACRO
imply SND_SOC_LPASS_TX_MACRO
imply SND_SOC_WL1273
@@ -1514,6 +1515,14 @@ config SND_SOC_WCD934X
  The WCD9340/9341 is a audio codec IC Integrated in
  Qualcomm SoCs like SDM845.
 
+config SND_SOC_WCD938X
+   tristate "WCD9380/WCD9385 Codec"
+   depends on SOUNDWIRE
+   select REGMAP_SOUNDWIRE
+   help
+ The WCD9380/9385 is a audio codec IC Integrated in
+ Qualcomm SoCs like SM8250.
+
 config SND_SOC_WL1273
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index dcc2f757bb82..287fe6b1a3d2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -248,6 +248,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
 snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
+snd-soc-wcd938x-objs := wcd938x.o wcd938x-sdw.o wcd-clsh-v2.o wcd938x-sdw.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -566,6 +567,7 @@ obj-$(CONFIG_SND_SOC_UDA134X)   += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WCD9335)  += snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)  += snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD938X)  += snd-soc-wcd938x.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM0010)   += snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
new file mode 100644
index ..ca29793b0972
--- /dev/null
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021, Linaro Limited
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "wcd938x.h"
+
+#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+   SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+   SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+SNDRV_PCM_RATE_176400)
+#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+   SNDRV_PCM_FMTBIT_S24_LE)
+#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
+};
+
+static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+   WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)),
+   WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)),
+   WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)),
+   WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)),
+   WCD_SDW_CH(WCD938X_DMIC7, WCD938X_

[PATCH v2 4/7] ASoC: codecs: wcd938x: add basic controls

2021-03-16 Thread Srinivas Kandagatla
This patch adds basic controls found in wcd938x codec.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd938x.c | 415 +
 1 file changed, 415 insertions(+)

diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index 9e8d588e2235..9b5dda775a17 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -66,6 +66,15 @@
 #define WCD938X_MBHC_MOISTURE_RREF  R_24_KOHM
 #define WCD_MBHC_HS_V_MAX   1600
 
+#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
+{  .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+   .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+   .tlv.p = (tlv_array), \
+   .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+   .put = wcd938x_ear_pa_put_gain, \
+   .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+
 enum {
WCD9380 = 0,
WCD9385 = 5,
@@ -187,6 +196,9 @@ enum {
 };
 
 static struct wcd938x_priv *g_wcd938x;
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000);
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
 
 static const struct reg_default wcd938x_defaults[] = {
{WCD938X_ANA_PAGE_REGISTER,0x00},
@@ -1275,6 +1287,380 @@ int wcd938x_io_init(struct wcd938x_sdw_priv *wcd)
 
 }
 
+static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+   struct sdw_port_config *port_config,
+   u32 mstr_port_num,
+   u8 enable)
+{
+   u8 ch_mask, port_num;
+
+   port_num = ch_info->port_num;
+   ch_mask = ch_info->ch_mask;
+
+   port_config->num = port_num;
+
+   if (enable)
+   port_config->ch_mask |= ch_mask;
+   else
+   port_config->ch_mask &= ~ch_mask;
+
+   return 0;
+}
+
+static int wcd938x_connect_port(struct snd_soc_component *component, u8 ch_id, 
u8 enable)
+{
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   u8 port_num, mstr_port_num;
+
+   port_num = wcd->ch_info[ch_id].port_num;
+   mstr_port_num = wcd->port_map[port_num - 1];
+
+   return wcd938x_sdw_connect_port(>ch_info[ch_id],
+   >port_config[port_num],
+   mstr_port_num,
+   enable);
+}
+
+static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   ucontrol->value.integer.value[0] = wcd938x->tx_mode[path];
+
+   return 0;
+}
+
+static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+   struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+   int path = e->shift_l;
+
+   wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   ucontrol->value.integer.value[0] = wcd938x->hph_mode;
+
+   return 0;
+}
+
+static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
+
+   return 0;
+}
+
+static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   s

[PATCH v2 2/7] ASoC: codecs: wcd-clsh: add new version support

2021-03-16 Thread Srinivas Kandagatla
>From WCD937X Class H controller has changed significantly, so add support
to this new version for WCD937X and WCD938X Codecs.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wcd-clsh-v2.c | 350 -
 sound/soc/codecs/wcd-clsh-v2.h |  16 ++
 2 files changed, 356 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index 817d8259758c..60e2e784d190 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -88,6 +88,19 @@ struct wcd_clsh_ctrl {
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50
 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
 
+#define WCD9XXX_BASE_ADDRESS   0x3000
+#define WCD9XXX_ANA_RX_SUPPLIES
(WCD9XXX_BASE_ADDRESS+0x008)
+#define WCD9XXX_ANA_HPH
(WCD9XXX_BASE_ADDRESS+0x009)
+#define WCD9XXX_CLASSH_MODE_2  
(WCD9XXX_BASE_ADDRESS+0x098)
+#define WCD9XXX_CLASSH_MODE_3  
(WCD9XXX_BASE_ADDRESS+0x099)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_1
(WCD9XXX_BASE_ADDRESS+0x0A5)
+#define WCD9XXX_FLYBACK_VNEG_CTRL_4
(WCD9XXX_BASE_ADDRESS+0x0A8)
+#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 
(WCD9XXX_BASE_ADDRESS+0x0AF)
+#define WCD9XXX_RX_BIAS_HPH_LOWPOWER   
(WCD9XXX_BASE_ADDRESS+0x0BF)
+#define WCD9XXX_V3_RX_BIAS_FLYB_BUFF   
(WCD9XXX_BASE_ADDRESS+0x0C7)
+#define WCD9XXX_HPH_PA_CTL1
(WCD9XXX_BASE_ADDRESS+0x0D1)
+#define WCD9XXX_HPH_NEW_INT_PA_MISC2   
(WCD9XXX_BASE_ADDRESS+0x138)
+
 #define CLSH_REQ_ENABLEtrue
 #define CLSH_REQ_DISABLE   false
 #define WCD_USLEEP_RANGE   50
@@ -137,6 +150,20 @@ static inline void wcd_clsh_set_buck_mode(struct 
snd_soc_component *comp,
WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
 }
 
+static inline void wcd_clsh_v3_set_buck_mode(struct snd_soc_component 
*component,
+ int mode)
+{
+   if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
+   mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x08); /* set to HIFI */
+   else
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   0x08, 0x00); /* set to default */
+}
+
 static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
 int mode)
 {
@@ -170,6 +197,36 @@ static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
usleep_range(500, 500 + WCD_USLEEP_RANGE);
 }
 
+static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component,
+  struct wcd_clsh_ctrl *ctrl,
+  int mode,
+  bool enable)
+{
+   /* enable/disable buck */
+   if ((enable && (++ctrl->buck_users == 1)) ||
+  (!enable && (--ctrl->buck_users == 0))) {
+   snd_soc_component_update_bits(component,
+   WCD9XXX_ANA_RX_SUPPLIES,
+   (1 << 7), (enable << 7));
+   /*
+* 500us sleep is required after buck enable/disable
+* as per HW requirement
+*/
+   usleep_range(500, 510);
+   if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
+   mode == CLS_H_HIFI || mode == CLS_H_LP)
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_3,
+   0x02, 0x00);
+
+   snd_soc_component_update_bits(component,
+   WCD9XXX_CLASSH_MODE_2,
+   0xFF, 0x3A);
+   /* 500usec delay is needed as per HW requirement */
+   usleep_range(500, 500 + WCD_USLEEP_RANGE);
+   }
+}
+
 static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl,
  int mode,
  bool enable)
@@ -219,8 +276,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl 
*ctrl, int mode)
val);
 }
 
-static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp,
- int mode)
+static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp,  int mode)
 {
int val = 0, gain = 0, res_val;
int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
@@ -264,6 +320,49 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component 
*comp,

[PATCH v2 1/7] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-03-16 Thread Srinivas Kandagatla
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire device RX and
TX respectively, supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs, MBHC.

Signed-off-by: Srinivas Kandagatla 
---
 .../bindings/sound/qcom,wcd938x.yaml  | 127 ++
 1 file changed, 127 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
new file mode 100644
index ..bac93e2344c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wcd938x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for Qualcomm WCD9380/WCD9385 Audio Codec
+
+maintainers:
+  - Srinivas Kandagatla 
+
+description: |
+  Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
+  It has RX and TX Soundwire slave devices.
+
+properties:
+  compatible:
+const: sdw20217010d00
+
+  reg:
+maxItems: 1
+
+  reset-gpios:
+description: GPIO spec for reset line to use
+maxItems: 1
+
+  direction:
+oneOf:
+  - const: rx
+  - const: tx
+
+  vdd-buck-supply:
+description: A reference to the 1.8V buck supply
+
+  vdd-rxtx-supply:
+description: A reference to the 1.8V rx supply
+
+  vdd-io-supply:
+description: A reference to the 1.8V I/O supply
+
+  qcom,micbias1-microvolt:
+description: micbias1 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias2-microvolt:
+description: micbias2 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias3-microvolt:
+description: micbias3 voltage
+minimum: 180
+maximum: 285
+
+  qcom,micbias4-microvolt:
+description: micbias4 voltage
+minimum: 180
+maximum: 285
+
+  qcom,mbhc-hphl-switch:
+description: Indicates that HPHL switch type is normally closed
+type: boolean
+
+  qcom,mbhc-ground-switch:
+description: Indicates that Headset Gound switch type is normally closed
+type: boolean
+
+  qcom,mbhc-vthreshold-microvolt:
+description: |
+  Voltage threshold values for all the headset buttons
+$ref: /schemas/types.yaml#/definitions/uint32-array
+minItems: 8
+maxItems: 8
+
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+$ref: /schemas/types.yaml#/definitions/uint32-array
+minItems: 4
+maxItems: 5
+
+  '#sound-dai-cells':
+const: 1
+
+required:
+  - compatible
+  - reg
+  - reset-gpios
+  - qcom,micbias1-microvolt
+  - qcom,micbias2-microvolt
+  - qcom,micbias3-microvolt
+  - qcom,micbias4-microvolt
+  - qcom,port-mapping
+  - qcom,mbhc-hphl-switch
+  - qcom,mbhc-ground-switch
+  - qcom,mbhc-vthreshold-microvolt
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+soundwire@323 {
+#address-cells = <2>;
+#size-cells = <0>;
+reg = <0x0323 0x2000>;
+
+codec@0,3 {
+compatible = "sdw20217010d00";
+reg  = <0 3>;
+reset-gpios = < 32 0>;
+direction = "tx";
+#sound-dai-cells = <1>;
+qcom,micbias1-microvolt = <180>;
+qcom,micbias2-microvolt = <180>;
+qcom,micbias3-microvolt = <180>;
+qcom,micbias4-microvolt = <180>;
+qcom,mbhc-hphl-switch;
+qcom,mbhc-ground-switch;
+qcom,mbhc-vthreshold-microvolt = <75000 15 237000 50 
50 50 50 50>;
+qcom,port-mapping = <2 3 4 5>;
+};
+};
+
+...
-- 
2.21.0



[PATCH v2 0/7] ASoC: codecs: add wcd938x support

2021-03-16 Thread Srinivas Kandagatla
This patchset adds support for Qualcomm WCD938X codec.

Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC
connected over SoundWire. This device has two SoundWire devices, RX and
TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH,
7 x TX diff inputs, 8 DMICs and MBHC.

Even though this device has two SoundWire devices, only tx device has
access to main codec Control/Status Registers!

This patchset along with other SoundWire patches on the list
have been tested on SM8250 MTP device.

Am planning to send support for MBHC once this driver gets accepted!

Thanks,
srini

Many thanks for reviewing v1.

Changes since v1:
- updated PA gain to a proper TLV control
- move various if else checks to switch case.
- return error on check failure rather than fallback to default
- cleaned up micbias pull up control
- fixed all the gain tlvs correctly
- update dt-bindings to use microvolt for button thresholds
- removed unnecessary debug at various places.

Srinivas Kandagatla (7):
  ASoC: dt-bindings: wcd938x: add bindings for wcd938x
  ASoC: codecs: wcd-clsh: add new version support
  ASoC: codecs: wcd938x: add basic driver
  ASoC: codecs: wcd938x: add basic controls
  ASoC: codecs: wcd938x: add playback dapm widgets
  ASoC: codecs: wcd938x: add capture dapm widgets
  ASoC: codecs: wcd938x: add audio routing

 .../bindings/sound/qcom,wcd938x.yaml  |  127 +
 sound/soc/codecs/Kconfig  |9 +
 sound/soc/codecs/Makefile |2 +
 sound/soc/codecs/wcd-clsh-v2.c|  350 +-
 sound/soc/codecs/wcd-clsh-v2.h|   16 +
 sound/soc/codecs/wcd938x-sdw.c|  291 ++
 sound/soc/codecs/wcd938x.c| 3623 +
 sound/soc/codecs/wcd938x.h|  676 +++
 8 files changed, 5084 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
 create mode 100644 sound/soc/codecs/wcd938x-sdw.c
 create mode 100644 sound/soc/codecs/wcd938x.c
 create mode 100644 sound/soc/codecs/wcd938x.h

-- 
2.21.0



[PATCH v4 4/5] ASoC: dt-bindings: wsa881x: add bindings for port mapping

2021-03-15 Thread Srinivas Kandagatla
WSA881x SoundWire device ports are statically assigned to master ports
at design time. So add bindings required to specify these mappings!

Signed-off-by: Srinivas Kandagatla 
---
 .../devicetree/bindings/sound/qcom,wsa881x.yaml  | 9 +
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
index ea44d03e58ca..491ce1270cb5 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
@@ -26,6 +26,13 @@ properties:
 description: GPIO spec for Powerdown/Shutdown line to use
 maxItems: 1
 
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+maxItems: 4
+$ref: /schemas/types.yaml#/definitions/uint32-array
+
   '#thermal-sensor-cells':
 const: 0
 
@@ -54,6 +61,7 @@ examples:
 powerdown-gpios = < 2 0>;
 #thermal-sensor-cells = <0>;
 #sound-dai-cells = <0>;
+qcom,port-mapping = <1 2 3 7>;
 };
 
 speaker@0,2 {
@@ -62,6 +70,7 @@ examples:
 powerdown-gpios = < 2 0>;
 #thermal-sensor-cells = <0>;
 #sound-dai-cells = <0>;
+qcom,port-mapping = <4 5 6 8>;
 };
 };
 
-- 
2.21.0



[PATCH v4 3/5] soundwire: qcom: add static port map support

2021-03-15 Thread Srinivas Kandagatla
SoundWire device ports are statically mapped to Controller ports during
design. Add support to read these from SoundWire devices.
This controller uses static port map info to setup bandwidth
parameters for those ports.

A generic port allocation is not possible in this cases!

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 9e70c53e2c7b..39222b04a2e0 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -460,6 +460,8 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt;
struct qcom_swrm_port_config *pcfg;
+   struct sdw_slave *slave;
+   unsigned int m_port;
int i = 0;
 
list_for_each_entry(m_rt, >m_rt_list, bus_node) {
@@ -473,8 +475,14 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
}
 
list_for_each_entry(s_rt, _rt->slave_rt_list, m_rt_node) {
+   slave = s_rt->slave;
list_for_each_entry(p_rt, _rt->port_list, port_node) {
-   pcfg = >pconfig[i];
+   m_port = slave->m_port_map[p_rt->num];
+   /* port config starts at offset 0 so -1 from 
actual port number */
+   if (m_port)
+   pcfg = >pconfig[m_port - 1];
+   else
+   pcfg = >pconfig[i];
p_rt->transport_params.port_num = p_rt->num;
p_rt->transport_params.sample_interval =
pcfg->si + 1;
@@ -535,8 +543,10 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt;
+   struct sdw_slave *slave;
unsigned long *port_mask;
int i, maxport, pn, nports = 0, ret = 0;
+   unsigned int m_port;
 
mutex_lock(>port_lock);
list_for_each_entry(m_rt, >master_list, stream_node) {
@@ -549,9 +559,15 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
}
 
list_for_each_entry(s_rt, _rt->slave_rt_list, m_rt_node) {
+   slave = s_rt->slave;
list_for_each_entry(p_rt, _rt->port_list, port_node) {
+   m_port = slave->m_port_map[p_rt->num];
/* Port numbers start from 1 - 14*/
-   pn = find_first_zero_bit(port_mask, maxport);
+   if (m_port)
+   pn = m_port;
+   else
+   pn = find_first_zero_bit(port_mask, 
maxport);
+
if (pn > maxport) {
dev_err(ctrl->dev, "All ports busy\n");
ret = -EBUSY;
-- 
2.21.0



[PATCH v4 5/5] ASoC: codecs: wsa881x: add static port map support

2021-03-15 Thread Srinivas Kandagatla
Two instances of WSA881x(Speaker Right, Speaker Left) ports
are statically mapped to master ports. Allow the driver to parse
those mappings from device tree.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wsa881x.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index db87e07b11c9..b3568aec0cd0 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1093,6 +1093,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
 const struct sdw_device_id *id)
 {
struct wsa881x_priv *wsa881x;
+   struct device *dev = >dev;
 
wsa881x = devm_kzalloc(>dev, sizeof(*wsa881x), GFP_KERNEL);
if (!wsa881x)
@@ -1105,6 +1106,12 @@ static int wsa881x_probe(struct sdw_slave *pdev,
return PTR_ERR(wsa881x->sd_n);
}
 
+   /* valid port numbers on this codec starts from 1, so skip 0th index */
+   if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping",
+  >m_port_map[1],
+  WSA881X_MAX_SWR_PORTS))
+   dev_info(dev, "Static Port mapping not specified\n");
+
dev_set_drvdata(>dev, wsa881x);
wsa881x->slave = pdev;
wsa881x->dev = >dev;
-- 
2.21.0



[PATCH v4 2/5] soundwire: qcom: update port map allocation bit mask

2021-03-15 Thread Srinivas Kandagatla
currently the internal bitmask used for allocating ports starts with offset 0.
This is bit confusing as data port numbers on Qualcomm controller are valid
from 1 to 14. So adjust this bit mask accordingly, this will also help while
adding static port map support.

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6d22df01f354..9e70c53e2c7b 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -519,7 +519,7 @@ static void qcom_swrm_stream_free_ports(struct 
qcom_swrm_ctrl *ctrl,
port_mask = >din_port_mask;
 
list_for_each_entry(p_rt, _rt->port_list, port_node)
-   clear_bit(p_rt->num - 1, port_mask);
+   clear_bit(p_rt->num, port_mask);
}
 
mutex_unlock(>port_lock);
@@ -552,13 +552,13 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
list_for_each_entry(p_rt, _rt->port_list, port_node) {
/* Port numbers start from 1 - 14*/
pn = find_first_zero_bit(port_mask, maxport);
-   if (pn > (maxport - 1)) {
+   if (pn > maxport) {
dev_err(ctrl->dev, "All ports busy\n");
ret = -EBUSY;
goto err;
}
set_bit(pn, port_mask);
-   pconfig[nports].num = pn + 1;
+   pconfig[nports].num = pn;
pconfig[nports].ch_mask = p_rt->ch_mask;
nports++;
}
@@ -580,7 +580,7 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
 err:
if (ret) {
for (i = 0; i < nports; i++)
-   clear_bit(pconfig[i].num - 1, port_mask);
+   clear_bit(pconfig[i].num, port_mask);
}
 
mutex_unlock(>port_lock);
@@ -754,6 +754,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl 
*ctrl)
ctrl->num_dout_ports = val;
 
nports = ctrl->num_dout_ports + ctrl->num_din_ports;
+   /* Valid port numbers are from 1-14, so mask out port 0 explicitly */
+   set_bit(0, >dout_port_mask);
+   set_bit(0, >din_port_mask);
 
ret = of_property_read_u8_array(np, "qcom,ports-offset1",
off1, nports);
-- 
2.21.0



[PATCH v4 1/5] soundwire: add static port mapping support

2021-03-15 Thread Srinivas Kandagatla
Some of the SoundWire device ports are statically mapped to Controller
ports during design, however there is no way to expose this information
to the controller. Controllers like Qualcomm ones use this info to setup
static bandwidth parameters for those ports.

A generic port allocation is not possible in this cases!
So this patch adds a new member m_port_map to struct sdw_slave to expose
this static map.

Signed-off-by: Srinivas Kandagatla 
---
 include/linux/soundwire/sdw.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index d08039d65825..2f52d6609076 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -614,6 +614,7 @@ struct sdw_slave_ops {
  * @debugfs: Slave debugfs
  * @node: node for bus list
  * @port_ready: Port ready completion flag for each Slave port
+ * @m_port_map: static Master port map for each Slave port
  * @dev_num: Current Device Number, values can be 0 or dev_num_sticky
  * @dev_num_sticky: one-time static Device Number assigned by Bus
  * @probed: boolean tracking driver state
@@ -645,6 +646,7 @@ struct sdw_slave {
 #endif
struct list_head node;
struct completion port_ready[SDW_MAX_PORTS];
+   unsigned int m_port_map[SDW_MAX_PORTS];
enum sdw_clk_stop_mode curr_clk_stop_mode;
u16 dev_num;
u16 dev_num_sticky;
-- 
2.21.0



[PATCH v4 0/5] soundwire: add static port map support

2021-03-15 Thread Srinivas Kandagatla
In some cases, SoundWire device ports are statically mapped to Controller
ports during design, however there is no way to expose this information
to the controller. Controllers like Qualcomm ones use this info to setup
static bandwidth parameters for those ports.

A generic port allocation is not possible in this cases!
This patch adds a new member m_port_map to SoundWire device so that
it can populate the static master port map and share it with controller
to be able to setup correct bandwidth parameters.

As a user of this feature this patchset also adds new bindings for
wsa881x smart speaker which has 4 ports which are statically mapped
to the 3 output and 1 input port of the controller.

Tested it on DB845c and SM8250 MTP.

thanks,
srini

Changes since v3:
- updated kernel doc for more clarity on m_port_map

Srinivas Kandagatla (5):
  soundwire: add static port mapping support
  soundwire: qcom: update port map allocation bit mask
  soundwire: qcom: add static port map support
  ASoC: dt-bindings: wsa881x: add bindings for port mapping
  ASoC: codecs: wsa881x: add static port map support

 .../bindings/sound/qcom,wsa881x.yaml  |  9 ++
 drivers/soundwire/qcom.c  | 31 +++
 include/linux/soundwire/sdw.h |  2 ++
 sound/soc/codecs/wsa881x.c|  7 +
 4 files changed, 43 insertions(+), 6 deletions(-)

-- 
2.21.0



[PATCH] nvmem: rmem: fix undefined reference to memremap

2021-03-15 Thread Srinivas Kandagatla
Fix below error reporte by kernel test robot
rmem.c:(.text+0x14e): undefined reference to memremap
s390x-linux-gnu-ld: rmem.c:(.text+0x1b6): undefined reference to memunmap

Reported-by: kernel test robot 
Signed-off-by: Srinivas Kandagatla 
---
 drivers/nvmem/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 642ddc699fd1..dd2019006838 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -272,6 +272,7 @@ config SPRD_EFUSE
 
 config NVMEM_RMEM
tristate "Reserved Memory Based Driver Support"
+   depends on HAS_IOMEM
help
  This driver maps reserved memory into an nvmem device. It might be
  useful to expose information left by firmware in memory.
-- 
2.21.0



Re: [PATCH 1/7] ASoC: dt-bindings: wcd938x: add bindings for wcd938x

2021-03-15 Thread Srinivas Kandagatla

Thanks for your feedback,

On 12/03/2021 15:21, Mark Brown wrote:

On Thu, Mar 11, 2021 at 05:34:10PM +, Srinivas Kandagatla wrote:


+  qcom,mbhc-hphl-switch:
+description: Indicates that HPHL switch type is normally closed!
+type: boolean
+
+  qcom,mbhc-ground-switch:
+description: Indicates that Headset Gound switch type is normally closed!
+type: boolean


Why do these descriptions have exclamation marks?


This was not intentional, will remove those instances in next version.

Thanks,
srini




Re: [PATCH 3/7] ASoC: codecs: wcd938x: add basic driver

2021-03-15 Thread Srinivas Kandagatla




On 12/03/2021 15:34, Mark Brown wrote:

On Thu, Mar 11, 2021 at 05:34:12PM +, Srinivas Kandagatla wrote:


+static int wcd9380_update_status(struct sdw_slave *slave,
+enum sdw_slave_status status)
+{
+   return 0;
+}
+
+static int wcd9380_port_prep(struct sdw_slave *slave,
+struct sdw_prepare_ch *prepare_ch,
+enum sdw_port_prep_ops state)
+{
+   return 0;
+}


If these can legitimately be empty I'd expect the framework to support
them being omitted.


One of them is not mandatory, I will revisit this before sending out 
next version.


thanks,
srini




Re: [PATCH 4/7] ASoC: codecs: wcd938x: add basic controls

2021-03-15 Thread Srinivas Kandagatla

Thanks Mark for review,

On 12/03/2021 15:55, Mark Brown wrote:

On Thu, Mar 11, 2021 at 05:34:13PM +, Srinivas Kandagatla wrote:


+   if (wcd938x->variant == WCD9380) {


switch statements please.


+   if (mode_val == CLS_H_HIFI || mode_val == CLS_AB_HIFI) {
+   dev_info(component->dev,
+   "%s:Invalid HPH Mode, default to CLS_H_ULP\n",
+   __func__);
+   mode_val = CLS_H_ULP;
+   }


If the value can't be set an error should be returned rather than the
input ignored.


I agree with all the comments related to switch statements and ignoring 
return values, will address them in next version.





+static int wcd938x_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+
+   ucontrol->value.integer.value[0] = 
snd_soc_component_read_field(component,
+   WCD938X_ANA_EAR_COMPANDER_CTL,
+   WCD938X_EAR_GAIN_MASK);
+
+   return 0;
+}


This just looks like a normal operation?


Yes, this can probably go into a TLV control, will fix this in next version.


--srini

+static int wcd938x_ear_pa_gain_put(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_component *component = 
snd_soc_kcontrol_component(kcontrol);
+   struct wcd938x_sdw_priv *wcd = snd_soc_component_get_drvdata(component);
+   struct wcd938x_priv *wcd938x = wcd->wcd938x;
+
+   if (!wcd938x->comp1_enable) {
+   snd_soc_component_write_field(component,
+   WCD938X_ANA_EAR_COMPANDER_CTL,
+   WCD938X_EAR_GAIN_MASK,
+   ucontrol->value.integer.value[0]);
+   }


Again, values should not be ignored on error.


+   if (wcd938x->variant == WCD9380) {
+   ret = snd_soc_add_component_controls(component, 
wcd9380_snd_controls,
+   ARRAY_SIZE(wcd9380_snd_controls));
+   if (ret < 0) {
+   dev_err(component->dev,
+   "%s: Failed to add snd ctrls for variant: %d\n",
+   __func__, wcd938x->variant);
+   goto err;
+   }
+   }
+   if (wcd938x->variant == WCD9385) {


Again, switch statements - I'll never understand why people seem so
intent on writing if trees :(



Re: [PATCH v3 1/5] soundwire: add static port mapping support

2021-03-15 Thread Srinivas Kandagatla




On 12/03/2021 16:56, Pierre-Louis Bossart wrote:



On 3/12/21 5:39 AM, Srinivas Kandagatla wrote:

Some of the SoundWire device ports are statically mapped to Controller
ports during design, however there is no way to expose this information
to the controller. Controllers like Qualcomm ones use this info to setup
static bandwidth parameters for those ports.

A generic port allocation is not possible in this cases!
So this patch adds a new member m_port_map to struct sdw_slave to expose
this static map.

Signed-off-by: Srinivas Kandagatla 
---
  include/linux/soundwire/sdw.h | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/include/linux/soundwire/sdw.h 
b/include/linux/soundwire/sdw.h

index d08039d65825..b032d6ac0b39 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -614,6 +614,7 @@ struct sdw_slave_ops {
   * @debugfs: Slave debugfs
   * @node: node for bus list
   * @port_ready: Port ready completion flag for each Slave port
+ * @m_port_map: static Master port map for each Slave port0 to port14


did you mean port1..port14?


Yes I agree its port1..port14, will update this in next version.

--srini
DP0 is a special case that's not supposed to be used for audio transport 
but rather extended control and command? >

   * @dev_num: Current Device Number, values can be 0 or dev_num_sticky
   * @dev_num_sticky: one-time static Device Number assigned by Bus
   * @probed: boolean tracking driver state
@@ -645,6 +646,7 @@ struct sdw_slave {
  #endif
  struct list_head node;
  struct completion port_ready[SDW_MAX_PORTS];
+    unsigned int m_port_map[SDW_MAX_PORTS];
  enum sdw_clk_stop_mode curr_clk_stop_mode;
  u16 dev_num;
  u16 dev_num_sticky;



[RESEND PATCH v3 5/5] ASoC: codecs: wsa881x: add static port map support

2021-03-12 Thread Srinivas Kandagatla
Two instances of WSA881x(Speaker Right, Speaker Left) ports
are statically mapped to master ports. Allow the driver to parse
those mappings from device tree.

Signed-off-by: Srinivas Kandagatla 
---
 sound/soc/codecs/wsa881x.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index db87e07b11c9..b3568aec0cd0 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1093,6 +1093,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
 const struct sdw_device_id *id)
 {
struct wsa881x_priv *wsa881x;
+   struct device *dev = >dev;
 
wsa881x = devm_kzalloc(>dev, sizeof(*wsa881x), GFP_KERNEL);
if (!wsa881x)
@@ -1105,6 +1106,12 @@ static int wsa881x_probe(struct sdw_slave *pdev,
return PTR_ERR(wsa881x->sd_n);
}
 
+   /* valid port numbers on this codec starts from 1, so skip 0th index */
+   if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping",
+  >m_port_map[1],
+  WSA881X_MAX_SWR_PORTS))
+   dev_info(dev, "Static Port mapping not specified\n");
+
dev_set_drvdata(>dev, wsa881x);
wsa881x->slave = pdev;
wsa881x->dev = >dev;
-- 
2.21.0



[RESEND PATCH v3 2/5] soundwire: qcom: update port map allocation bit mask

2021-03-12 Thread Srinivas Kandagatla
currently the internal bitmask used for allocating ports starts with offset 0.
This is bit confusing as data port numbers on Qualcomm controller are valid
from 1 to 14. So adjust this bit mask accordingly, this will also help while
adding static port map support.

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6d22df01f354..9e70c53e2c7b 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -519,7 +519,7 @@ static void qcom_swrm_stream_free_ports(struct 
qcom_swrm_ctrl *ctrl,
port_mask = >din_port_mask;
 
list_for_each_entry(p_rt, _rt->port_list, port_node)
-   clear_bit(p_rt->num - 1, port_mask);
+   clear_bit(p_rt->num, port_mask);
}
 
mutex_unlock(>port_lock);
@@ -552,13 +552,13 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
list_for_each_entry(p_rt, _rt->port_list, port_node) {
/* Port numbers start from 1 - 14*/
pn = find_first_zero_bit(port_mask, maxport);
-   if (pn > (maxport - 1)) {
+   if (pn > maxport) {
dev_err(ctrl->dev, "All ports busy\n");
ret = -EBUSY;
goto err;
}
set_bit(pn, port_mask);
-   pconfig[nports].num = pn + 1;
+   pconfig[nports].num = pn;
pconfig[nports].ch_mask = p_rt->ch_mask;
nports++;
}
@@ -580,7 +580,7 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
 err:
if (ret) {
for (i = 0; i < nports; i++)
-   clear_bit(pconfig[i].num - 1, port_mask);
+   clear_bit(pconfig[i].num, port_mask);
}
 
mutex_unlock(>port_lock);
@@ -754,6 +754,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl 
*ctrl)
ctrl->num_dout_ports = val;
 
nports = ctrl->num_dout_ports + ctrl->num_din_ports;
+   /* Valid port numbers are from 1-14, so mask out port 0 explicitly */
+   set_bit(0, >dout_port_mask);
+   set_bit(0, >din_port_mask);
 
ret = of_property_read_u8_array(np, "qcom,ports-offset1",
off1, nports);
-- 
2.21.0



[RESEND PATCH v3 3/5] soundwire: qcom: add static port map support

2021-03-12 Thread Srinivas Kandagatla
SoundWire device ports are statically mapped to Controller ports during
design. Add support to read these from SoundWire devices.
This controller uses static port map info to setup bandwidth
parameters for those ports.

A generic port allocation is not possible in this cases!

Signed-off-by: Srinivas Kandagatla 
---
 drivers/soundwire/qcom.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 9e70c53e2c7b..39222b04a2e0 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -460,6 +460,8 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt;
struct qcom_swrm_port_config *pcfg;
+   struct sdw_slave *slave;
+   unsigned int m_port;
int i = 0;
 
list_for_each_entry(m_rt, >m_rt_list, bus_node) {
@@ -473,8 +475,14 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
}
 
list_for_each_entry(s_rt, _rt->slave_rt_list, m_rt_node) {
+   slave = s_rt->slave;
list_for_each_entry(p_rt, _rt->port_list, port_node) {
-   pcfg = >pconfig[i];
+   m_port = slave->m_port_map[p_rt->num];
+   /* port config starts at offset 0 so -1 from 
actual port number */
+   if (m_port)
+   pcfg = >pconfig[m_port - 1];
+   else
+   pcfg = >pconfig[i];
p_rt->transport_params.port_num = p_rt->num;
p_rt->transport_params.sample_interval =
pcfg->si + 1;
@@ -535,8 +543,10 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt;
+   struct sdw_slave *slave;
unsigned long *port_mask;
int i, maxport, pn, nports = 0, ret = 0;
+   unsigned int m_port;
 
mutex_lock(>port_lock);
list_for_each_entry(m_rt, >master_list, stream_node) {
@@ -549,9 +559,15 @@ static int qcom_swrm_stream_alloc_ports(struct 
qcom_swrm_ctrl *ctrl,
}
 
list_for_each_entry(s_rt, _rt->slave_rt_list, m_rt_node) {
+   slave = s_rt->slave;
list_for_each_entry(p_rt, _rt->port_list, port_node) {
+   m_port = slave->m_port_map[p_rt->num];
/* Port numbers start from 1 - 14*/
-   pn = find_first_zero_bit(port_mask, maxport);
+   if (m_port)
+   pn = m_port;
+   else
+   pn = find_first_zero_bit(port_mask, 
maxport);
+
if (pn > maxport) {
dev_err(ctrl->dev, "All ports busy\n");
ret = -EBUSY;
-- 
2.21.0



[RESEND PATCH v3 4/5] ASoC: dt-bindings: wsa881x: add bindings for port mapping

2021-03-12 Thread Srinivas Kandagatla
WSA881x SoundWire device ports are statically assigned to master ports
at design time. So add bindings required to specify these mappings!

Signed-off-by: Srinivas Kandagatla 
---
 .../devicetree/bindings/sound/qcom,wsa881x.yaml  | 9 +
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml 
b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
index ea44d03e58ca..491ce1270cb5 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa881x.yaml
@@ -26,6 +26,13 @@ properties:
 description: GPIO spec for Powerdown/Shutdown line to use
 maxItems: 1
 
+  qcom,port-mapping:
+description: |
+  Specifies static port mapping between slave and master ports.
+  In the order of slave port index.
+maxItems: 4
+$ref: /schemas/types.yaml#/definitions/uint32-array
+
   '#thermal-sensor-cells':
 const: 0
 
@@ -54,6 +61,7 @@ examples:
 powerdown-gpios = < 2 0>;
 #thermal-sensor-cells = <0>;
 #sound-dai-cells = <0>;
+qcom,port-mapping = <1 2 3 7>;
 };
 
 speaker@0,2 {
@@ -62,6 +70,7 @@ examples:
 powerdown-gpios = < 2 0>;
 #thermal-sensor-cells = <0>;
 #sound-dai-cells = <0>;
+qcom,port-mapping = <4 5 6 8>;
 };
 };
 
-- 
2.21.0



[RESEND PATCH v3 1/5] soundwire: add static port mapping support

2021-03-12 Thread Srinivas Kandagatla
Some of the SoundWire device ports are statically mapped to Controller
ports during design, however there is no way to expose this information
to the controller. Controllers like Qualcomm ones use this info to setup
static bandwith parameters for those ports.

A generic port allocation is not possible in this cases!
So this patch adds a new member m_port_map to struct sdw_slave to expose
this static map.

Signed-off-by: Srinivas Kandagatla 
---
 include/linux/soundwire/sdw.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index d08039d65825..b032d6ac0b39 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -614,6 +614,7 @@ struct sdw_slave_ops {
  * @debugfs: Slave debugfs
  * @node: node for bus list
  * @port_ready: Port ready completion flag for each Slave port
+ * @m_port_map: static Master port map for each Slave port0 to port14
  * @dev_num: Current Device Number, values can be 0 or dev_num_sticky
  * @dev_num_sticky: one-time static Device Number assigned by Bus
  * @probed: boolean tracking driver state
@@ -645,6 +646,7 @@ struct sdw_slave {
 #endif
struct list_head node;
struct completion port_ready[SDW_MAX_PORTS];
+   unsigned int m_port_map[SDW_MAX_PORTS];
enum sdw_clk_stop_mode curr_clk_stop_mode;
u16 dev_num;
u16 dev_num_sticky;
-- 
2.21.0



  1   2   3   4   5   6   7   8   9   10   >