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 with tx if it helps.


+
+static struct regmap_config wcd938x_regmap_config = {
+    .name = "wcd938x_csr",
+    .reg_bits = 32,
+    

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

2021-03-19 Thread Pierre-Louis Bossart




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.


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?



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


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?



+
+static struct regmap_config wcd938x_regmap_config = {
+   .name = "wcd938x_csr",
+   .reg_bits = 32,
+   

[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_DMIC_4_7_PORT, BIT(3)),
+};
+