OK - on close inspection of the adcx140_i2c_probe() function in the TI driver, it would appear that the wrong pointer arguments have been passed, so the reset GPIO can never be captured correctly. The diff of my new driver file v the original is as follows:
diff --git a/tlv320adcx140_orig.c b/tlv320adcx140.c
index 8bab398..6da5b4a 100644
--- a/tlv320adcx140_orig.c
+++ b/tlv320adcx140.c
@@ -24,7 +24,7 @@
#include "tlv320adcx140.h"
struct adcx140_priv {
- struct snd_soc_component *component;
+ struct snd_soc_codec *codec;
struct regulator *supply_areg;
struct gpio_desc *gpio_reset;
struct regmap *regmap;
@@ -550,12 +550,20 @@ static int adcx140_reset(struct adcx140_priv *adcx140)
{
int ret = 0;
+ dev_info(adcx140->dev, "Attempting to reset tlv320adcx140...\n");
+
if (adcx140->gpio_reset) {
+
+ dev_info(adcx140->dev, "Attempting HW reset...\n");
+
gpiod_direction_output(adcx140->gpio_reset, 0);
/* 8.4.1: wait for hw shutdown (25ms) + >= 1ms */
usleep_range(30000, 100000);
gpiod_direction_output(adcx140->gpio_reset, 1);
} else {
+
+ dev_info(adcx140->dev, "Attempting SW reset...\n");
+
ret = regmap_write(adcx140->regmap, ADCX140_SW_RESET,
ADCX140_RESET);
}
@@ -563,14 +571,14 @@ static int adcx140_reset(struct adcx140_priv *adcx140)
/* 8.4.2: wait >= 10 ms after entering sleep mode. */
usleep_range(10000, 100000);
- return 0;
+ return ret;
}
static int adcx140_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_component *component = dai->component;
+ struct snd_soc_codec *codec = dai->codec;
u8 data = 0;
switch (params_width(params)) {
@@ -587,12 +595,12 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream,
data = ADCX140_32_BIT_WORD;
break;
default:
- dev_err(component->dev, "%s: Unsupported width %d\n",
+ dev_err(codec->dev, "%s: Unsupported width %d\n",
__func__, params_width(params));
return -EINVAL;
}
- snd_soc_component_update_bits(component, ADCX140_ASI_CFG0,
+ snd_soc_update_bits(codec, ADCX140_ASI_CFG0,
ADCX140_WORD_LEN_MSK, data);
return 0;
@@ -601,8 +609,8 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream,
static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
- struct snd_soc_component *component = codec_dai->component;
- struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct adcx140_priv *adcx140 = snd_soc_codec_get_drvdata(codec);
u8 iface_reg1 = 0;
u8 iface_reg2 = 0;
@@ -616,7 +624,7 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_CBS_CFM:
case SND_SOC_DAIFMT_CBM_CFS:
default:
- dev_err(component->dev, "Invalid DAI master/slave interface\n");
+ dev_err(codec->dev, "Invalid DAI master/slave interface\n");
return -EINVAL;
}
@@ -634,7 +642,7 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_NB_NF:
break;
default:
- dev_err(component->dev, "Invalid DAI clock signal polarity\n");
+ dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
return -EINVAL;
}
@@ -650,18 +658,18 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_DSP_B:
break;
default:
- dev_err(component->dev, "Invalid DAI interface format\n");
+ dev_err(codec->dev, "Invalid DAI interface format\n");
return -EINVAL;
}
adcx140->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
- snd_soc_component_update_bits(component, ADCX140_ASI_CFG0,
+ snd_soc_update_bits(codec, ADCX140_ASI_CFG0,
ADCX140_FSYNCINV_BIT |
ADCX140_BCLKINV_BIT |
ADCX140_ASI_FORMAT_MSK,
iface_reg1);
- snd_soc_component_update_bits(component, ADCX140_MST_CFG0,
+ snd_soc_update_bits(codec, ADCX140_MST_CFG0,
ADCX140_BCLK_FSYNC_MASTER, iface_reg2);
return 0;
@@ -671,19 +679,19 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
{
- struct snd_soc_component *component = codec_dai->component;
- struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct adcx140_priv *adcx140 = snd_soc_codec_get_drvdata(codec);
unsigned int lsb;
if (tx_mask != rx_mask) {
- dev_err(component->dev, "tx and rx masks must be symmetric\n");
+ dev_err(codec->dev, "tx and rx masks must be symmetric\n");
return -EINVAL;
}
/* TDM based on DSP mode requires slots to be adjacent */
lsb = __ffs(tx_mask);
if ((lsb + 1) != __fls(tx_mask)) {
- dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+ dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
return -EINVAL;
}
@@ -694,7 +702,7 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
case 32:
break;
default:
- dev_err(component->dev, "Unsupported slot width %d\n", slot_width);
+ dev_err(codec->dev, "Unsupported slot width %d\n", slot_width);
return -EINVAL;
}
@@ -707,8 +715,8 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
static int adcx140_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_component *component = dai->component;
- struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_codec *codec = dai->codec;
+ struct adcx140_priv *adcx140 = snd_soc_codec_get_drvdata(codec);
int offset = 0;
int width = adcx140->slot_width;
@@ -722,7 +730,7 @@ static int adcx140_prepare(struct snd_pcm_substream *substream,
offset += adcx140->tdm_delay * width;
/* Configure data offset */
- snd_soc_component_update_bits(component, ADCX140_ASI_CFG1,
+ snd_soc_update_bits(codec, ADCX140_ASI_CFG1,
ADCX140_TX_OFFSET_MASK, offset);
return 0;
@@ -735,14 +743,16 @@ static const struct snd_soc_dai_ops adcx140_dai_ops = {
.set_tdm_slot = adcx140_set_dai_tdm_slot,
};
-static int adcx140_codec_probe(struct snd_soc_component *component)
+static int adcx140_codec_probe(struct snd_soc_codec *codec)
{
- struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
+ struct adcx140_priv *adcx140 = snd_soc_codec_get_drvdata(codec);
int sleep_cfg_val = ADCX140_WAKE_DEV;
u8 bias_source;
u8 vref_source;
int ret;
+ dev_info(adcx140->dev, "Entered adcx140_codec_probe\n");
+
ret = device_property_read_u8(adcx140->dev, "ti,mic-bias-source",
&bias_source);
if (ret)
@@ -792,10 +802,10 @@ out:
return ret;
}
-static int adcx140_set_bias_level(struct snd_soc_component *component,
+static int adcx140_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
+ struct adcx140_priv *adcx140 = snd_soc_codec_get_drvdata(codec);
int pwr_cfg = 0;
switch (level) {
@@ -813,20 +823,22 @@ static int adcx140_set_bias_level(struct snd_soc_component *component,
return regmap_write(adcx140->regmap, ADCX140_PWR_CFG, pwr_cfg);
}
-static const struct snd_soc_component_driver soc_codec_driver_adcx140 = {
- .probe = adcx140_codec_probe,
- .set_bias_level = adcx140_set_bias_level,
- .controls = adcx140_snd_controls,
- .num_controls = ARRAY_SIZE(adcx140_snd_controls),
- .dapm_widgets = adcx140_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(adcx140_dapm_widgets),
- .dapm_routes = adcx140_audio_map,
- .num_dapm_routes = ARRAY_SIZE(adcx140_audio_map),
- .suspend_bias_off = 1,
- .idle_bias_on = 0,
- .use_pmdown_time = 1,
- .endianness = 1,
- .non_legacy_dai_naming = 1,
+static const struct snd_soc_codec_driver soc_codec_driver_adcx140 = {
+ .probe = adcx140_codec_probe,
+ .set_bias_level = adcx140_set_bias_level,
+ .suspend_bias_off = true,
+ .idle_bias_off = true,
+ .ignore_pmdown_time = false,
+/* .endianness = true,*/
+/* .non_legacy_dai_naming = true,*/
+ .component_driver = {
+ .controls = adcx140_snd_controls,
+ .num_controls = ARRAY_SIZE(adcx140_snd_controls),
+ .dapm_widgets = adcx140_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adcx140_dapm_widgets),
+ .dapm_routes = adcx140_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(adcx140_audio_map),
+ },
};
static struct snd_soc_dai_driver adcx140_dai_driver[] = {
@@ -836,8 +848,8 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = ADCX140_MAX_CHANNELS,
- .rates = ADCX140_RATES,
- .formats = ADCX140_FORMATS,
+ .rates = ADCX140_RATES,
+ .formats = ADCX140_FORMATS,
},
.ops = &adcx140_dai_ops,
.symmetric_rates = 1,
@@ -862,22 +874,28 @@ static int adcx140_i2c_probe(struct i2c_client *i2c,
if (!adcx140)
return -ENOMEM;
- adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev,
+ adcx140->gpio_reset = devm_gpiod_get_optional(&i2c->dev,
"reset", GPIOD_OUT_LOW);
- if (IS_ERR(adcx140->gpio_reset))
- dev_info(&i2c->dev, "Reset GPIO not defined\n");
- adcx140->supply_areg = devm_regulator_get_optional(adcx140->dev,
+ if (adcx140->gpio_reset)
+ dev_info(&i2c->dev, "Got reset GPIO %d OK\n",
+ desc_to_gpio(adcx140->gpio_reset));
+ else
+ dev_err(&i2c->dev, "Reset GPIO not defined!\n");
+
+ adcx140->supply_areg = devm_regulator_get_optional(&i2c->dev,
"areg");
+
if (IS_ERR(adcx140->supply_areg)) {
- if (PTR_ERR(adcx140->supply_areg) == -EPROBE_DEFER)
+ if (PTR_ERR(adcx140->supply_areg) == -EPROBE_DEFER) {
+ dev_err(&i2c->dev, "Probe deferred...\n");
return -EPROBE_DEFER;
- else
+ } else
adcx140->supply_areg = NULL;
} else {
ret = regulator_enable(adcx140->supply_areg);
if (ret) {
- dev_err(adcx140->dev, "Failed to enable areg\n");
+ dev_err(&i2c->dev, "Failed to enable areg\n");
return ret;
}
}
@@ -889,12 +907,19 @@ static int adcx140_i2c_probe(struct i2c_client *i2c,
ret);
return ret;
}
+
adcx140->dev = &i2c->dev;
i2c_set_clientdata(i2c, adcx140);
- return devm_snd_soc_register_component(&i2c->dev,
+ dev_info(adcx140->dev, "Calling snd_soc_register_codec():\n");
+
+ ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_driver_adcx140,
adcx140_dai_driver, 1);
+
+ dev_info(adcx140->dev, "Return value = %d\n", ret);
+
+ return ret;
}
static const struct i2c_device_id adcx140_i2c_id[] = {
@@ -917,4 +942,4 @@ module_i2c_driver(adcx140_i2c_driver);
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
MODULE_DESCRIPTION("ASoC TLV320ADCX140 CODEC Driver");
-MODULE_LICENSE("GPL v2");
\ No newline at end of file
+MODULE_LICENSE("GPL v2");
Having fixed this, I am now on to the next problem, which is a failure to register the DAI:
tegra-asoc: sound: ASoC: CODEC DAI tlv320adcx140 not registered.
I am wondering if this could be caused by incorrect routing???
What I have is below, which is a total guess and bound to be wrong:
tegra_sound: sound {
compatible = "nvidia,tegra-audio-t186ref-mobile-rt565x";
nvidia,model = "tegra-snd-t186ref-mobile-rt565x";
nvidia,num-codec-link = <1>;
nvidia,num-clk = <8>;
nvidia,clk-rates = < 270950400 /* PLLA_x11025_RATE */
11289600 /* AUD_MCLK_x11025_RATE */
45158400 /* PLLA_OUT0_x11025_RATE */
45158400 /* AHUB_x11025_RATE */
245760000 /* PLLA_x8000_RATE */
12288000 /* AUD_MCLK_x8000_RATE */
49152000 /* PLLA_OUT0_x8000_RATE */
49152000 >;/* AHUB_x8000_RATE */
clocks = <&tegra_car TEGRA186_CLK_PLLP_OUT0>,
<&tegra_car TEGRA186_CLK_PLLA>,
<&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA186_CLK_AHUB>,
<&tegra_car TEGRA186_CLK_CLK_M>,
<&tegra_car TEGRA186_CLK_AUD_MCLK>;
clock-names = "pll_p_out1", "pll_a", "pll_a_out0", "ahub",
"clk_m", "extern1";
/*
clocks = <&tegra_car TEGRA186_CLK_PLLA>,
<&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA186_CLK_AHUB>,
<&tegra_car TEGRA186_CLK_AUD_MCLK>;
clock-names = "pll_a", "pll_a_out0", "ahub", "extern1";
*/ assigned-clocks = <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA186_CLK_AHUB>,
<&tegra_car TEGRA186_CLK_AUD_MCLK>;
assigned-clock-parents = <&tegra_car TEGRA186_CLK_PLLA>,
<&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA186_CLK_PLL_A_OUT0>;
resets = <&tegra_car TEGRA186_RESET_AUD_MCLK>;
reset-names = "extern1_rst";
status = "okay";
nvidia,audio-routing =
"x CH1_ADC", "x Mic",
"x CH2_ADC", "x Mic",
"x CH3_ADC", "x Mic",
"x CH4_ADC", "x Mic";
nvidia,xbar = <&tegra_axbar>;
mclk-fs = <256>;
rt565x_dai_link: nvidia,dai-link-1 {
link-name = "tlv320adcx140-codec";
cpu-dai = <&tegra_i2s1>;
codec-dai = <&tlv320adcx140>;
cpu-dai-name = "I2S1";
codec-dai-name = "tlv320adcx140";
format = "dsp-a";
fsync-width = <15>;
bitclock-slave;
frame-slave;
bitclock-noninversion;
frame-noninversion;
bit-format = "s16_le";
bclk_ratio = <1>;
srate = <48000>;
num-channel = <4>;
ignore_suspend;
name-prefix = "x";
status = "okay";
};