aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/tegra/tegra210_i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra210_i2s.c')
-rw-r--r--sound/soc/tegra/tegra210_i2s.c319
1 files changed, 236 insertions, 83 deletions
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index a383bd5c51cd..ba7fdd7405ac 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -6,8 +6,8 @@
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -214,11 +214,11 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int mask, val;
mask = I2S_CTRL_MASTER_EN_MASK;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
val = 0;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BP_FP:
val = I2S_CTRL_MASTER_EN;
break;
default:
@@ -302,85 +302,235 @@ static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
-static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
- unsigned int ratio)
+static int tegra210_i2s_get_loopback(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
- i2s->bclk_ratio = ratio;
+ ucontrol->value.integer.value[0] = i2s->loopback;
return 0;
}
-static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_put_loopback(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ int value = ucontrol->value.integer.value[0];
+
+ if (value == i2s->loopback)
+ return 0;
+
+ i2s->loopback = value;
+
+ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, I2S_CTRL_LPBK_MASK,
+ i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+ return 1;
+}
+
+static int tegra210_i2s_get_fsync_width(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
- long *uctl_val = &ucontrol->value.integer.value[0];
-
- if (strstr(kcontrol->id.name, "Loopback"))
- *uctl_val = i2s->loopback;
- else if (strstr(kcontrol->id.name, "FSYNC Width"))
- *uctl_val = i2s->fsync_width;
- else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
- *uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
- else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
- *uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
- else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
- *uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
- else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
- *uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
- else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
- *uctl_val = i2s->rx_fifo_th;
- else if (strstr(kcontrol->id.name, "BCLK Ratio"))
- *uctl_val = i2s->bclk_ratio;
+
+ ucontrol->value.integer.value[0] = i2s->fsync_width;
return 0;
}
-static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_put_fsync_width(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
int value = ucontrol->value.integer.value[0];
- if (strstr(kcontrol->id.name, "Loopback")) {
- i2s->loopback = value;
+ if (value == i2s->fsync_width)
+ return 0;
- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
- I2S_CTRL_LPBK_MASK,
- i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+ i2s->fsync_width = value;
- } else if (strstr(kcontrol->id.name, "FSYNC Width")) {
- /*
- * Frame sync width is used only for FSYNC modes and not
- * applicable for LRCK modes. Reset value for this field is "0",
- * which means the width is one bit clock wide.
- * The width requirement may depend on the codec and in such
- * cases mixer control is used to update custom values. A value
- * of "N" here means, width is "N + 1" bit clock wide.
- */
- i2s->fsync_width = value;
-
- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
- I2S_CTRL_FSYNC_WIDTH_MASK,
- i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
-
- } else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
- i2s->stereo_to_mono[I2S_TX_PATH] = value;
- } else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
- i2s->mono_to_stereo[I2S_TX_PATH] = value;
- } else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
- i2s->stereo_to_mono[I2S_RX_PATH] = value;
- } else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
- i2s->mono_to_stereo[I2S_RX_PATH] = value;
- } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
- i2s->rx_fifo_th = value;
- } else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
- i2s->bclk_ratio = value;
- }
+ /*
+ * Frame sync width is used only for FSYNC modes and not
+ * applicable for LRCK modes. Reset value for this field is "0",
+ * which means the width is one bit clock wide.
+ * The width requirement may depend on the codec and in such
+ * cases mixer control is used to update custom values. A value
+ * of "N" here means, width is "N + 1" bit clock wide.
+ */
+ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+ I2S_CTRL_FSYNC_WIDTH_MASK,
+ i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+ return 1;
+}
+
+static int tegra210_i2s_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_TX_PATH];
+
+ return 0;
+}
+
+static int tegra210_i2s_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+
+ if (value == i2s->stereo_to_mono[I2S_TX_PATH])
+ return 0;
+
+ i2s->stereo_to_mono[I2S_TX_PATH] = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_TX_PATH];
+
+ return 0;
+}
+
+static int tegra210_i2s_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+
+ if (value == i2s->mono_to_stereo[I2S_TX_PATH])
+ return 0;
+
+ i2s->mono_to_stereo[I2S_TX_PATH] = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_RX_PATH];
+
+ return 0;
+}
+
+static int tegra210_i2s_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+
+ if (value == i2s->stereo_to_mono[I2S_RX_PATH])
+ return 0;
+
+ i2s->stereo_to_mono[I2S_RX_PATH] = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_RX_PATH];
+
+ return 0;
+}
+
+static int tegra210_i2s_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+
+ if (value == i2s->mono_to_stereo[I2S_RX_PATH])
+ return 0;
+
+ i2s->mono_to_stereo[I2S_RX_PATH] = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_pget_fifo_th(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.integer.value[0] = i2s->rx_fifo_th;
+
+ return 0;
+}
+
+static int tegra210_i2s_pput_fifo_th(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ int value = ucontrol->value.integer.value[0];
+
+ if (value == i2s->rx_fifo_th)
+ return 0;
+
+ i2s->rx_fifo_th = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+ ucontrol->value.integer.value[0] = i2s->bclk_ratio;
+
+ return 0;
+}
+
+static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+ int value = ucontrol->value.integer.value[0];
+
+ if (value == i2s->bclk_ratio)
+ return 0;
+
+ i2s->bclk_ratio = value;
+
+ return 1;
+}
+
+static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+ unsigned int ratio)
+{
+ struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ i2s->bclk_ratio = ratio;
return 0;
}
@@ -577,7 +727,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &tegra210_i2s_dai_ops,
- .symmetric_rates = 1,
+ .symmetric_rate = 1,
},
};
@@ -598,22 +748,28 @@ static const struct soc_enum tegra210_i2s_stereo_conv_enum =
tegra210_i2s_stereo_conv_text);
static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
- SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
- tegra210_i2s_put_control),
- SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
- tegra210_i2s_put_control),
+ SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_loopback,
+ tegra210_i2s_put_loopback),
+ SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0,
+ tegra210_i2s_get_fsync_width,
+ tegra210_i2s_put_fsync_width),
SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
- tegra210_i2s_get_control, tegra210_i2s_put_control),
+ tegra210_i2s_cget_stereo_to_mono,
+ tegra210_i2s_cput_stereo_to_mono),
SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
- tegra210_i2s_get_control, tegra210_i2s_put_control),
+ tegra210_i2s_cget_mono_to_stereo,
+ tegra210_i2s_cput_mono_to_stereo),
SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
- tegra210_i2s_get_control, tegra210_i2s_put_control),
+ tegra210_i2s_pget_mono_to_stereo,
+ tegra210_i2s_pput_mono_to_stereo),
SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
- tegra210_i2s_get_control, tegra210_i2s_put_control),
+ tegra210_i2s_pget_stereo_to_mono,
+ tegra210_i2s_pput_stereo_to_mono),
SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
- 0, tegra210_i2s_get_control, tegra210_i2s_put_control),
- SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
- tegra210_i2s_put_control),
+ 0, tegra210_i2s_pget_fifo_th, tegra210_i2s_pput_fifo_th),
+ SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0,
+ tegra210_i2s_get_bclk_ratio,
+ tegra210_i2s_put_bclk_ratio),
};
static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
@@ -647,7 +803,6 @@ static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
.num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
.controls = tegra210_i2s_controls,
.num_controls = ARRAY_SIZE(tegra210_i2s_controls),
- .non_legacy_dai_naming = 1,
};
static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
@@ -662,7 +817,7 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
@@ -682,7 +837,7 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -701,7 +856,7 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra210_i2s_regmap_config = {
@@ -776,11 +931,9 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
return 0;
}
-static int tegra210_i2s_remove(struct platform_device *pdev)
+static void tegra210_i2s_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct dev_pm_ops tegra210_i2s_pm_ops = {
@@ -803,7 +956,7 @@ static struct platform_driver tegra210_i2s_driver = {
.pm = &tegra210_i2s_pm_ops,
},
.probe = tegra210_i2s_probe,
- .remove = tegra210_i2s_remove,
+ .remove_new = tegra210_i2s_remove,
};
module_platform_driver(tegra210_i2s_driver)