summaryrefslogtreecommitdiff
path: root/sound/soc/sunxi
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sunxi')
-rw-r--r--sound/soc/sunxi/sun4i-codec.c3
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c115
-rw-r--r--sound/soc/sunxi/sun8i-codec.c56
3 files changed, 172 insertions, 2 deletions
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index da597e456beb..60712f24ade5 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -1752,8 +1752,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
GPIOD_OUT_LOW);
if (IS_ERR(scodec->gpio_pa)) {
ret = PTR_ERR(scodec->gpio_pa);
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
return ret;
}
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index a10949bf0ca1..17090f43150e 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -21,6 +21,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <sound/asoundef.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -186,6 +188,7 @@ struct sun4i_spdif_dev {
struct regmap *regmap;
struct snd_dmaengine_dai_dma_data dma_params_tx;
const struct sun4i_spdif_quirks *quirks;
+ spinlock_t lock;
};
static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
@@ -385,11 +388,122 @@ static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static int sun4i_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 *status = ucontrol->value.iec958.status;
+
+ status[0] = 0xff;
+ status[1] = 0xff;
+ status[2] = 0xff;
+ status[3] = 0xff;
+ status[4] = 0xff;
+ status[5] = 0x03;
+
+ return 0;
+}
+
+static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+ u8 *status = ucontrol->value.iec958.status;
+ unsigned long flags;
+ unsigned int reg;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, &reg);
+
+ status[0] = reg & 0xff;
+ status[1] = (reg >> 8) & 0xff;
+ status[2] = (reg >> 16) & 0xff;
+ status[3] = (reg >> 24) & 0xff;
+
+ regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, &reg);
+
+ status[4] = reg & 0xff;
+ status[5] = (reg >> 8) & 0x3;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+
+static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+ u8 *status = ucontrol->value.iec958.status;
+ unsigned long flags;
+ unsigned int reg;
+ bool chg0, chg1;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ reg = (u32)status[3] << 24;
+ reg |= (u32)status[2] << 16;
+ reg |= (u32)status[1] << 8;
+ reg |= (u32)status[0];
+
+ regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
+ GENMASK(31,0), reg, &chg0);
+
+ reg = (u32)status[5] << 8;
+ reg |= (u32)status[4];
+
+ regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
+ GENMASK(9,0), reg, &chg1);
+
+ reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
+ if (status[0] & IEC958_AES0_NONAUDIO)
+ reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
+
+ regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
+ SUN4I_SPDIF_TXCFG_CHSTMODE |
+ SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return chg0 || chg1;
+}
+
+static struct snd_kcontrol_new sun4i_spdif_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+ .info = sun4i_spdif_info,
+ .get = sun4i_spdif_get_status_mask
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = sun4i_spdif_info,
+ .get = sun4i_spdif_get_status,
+ .put = sun4i_spdif_set_status
+ }
+};
+
static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
{
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
+ snd_soc_add_dai_controls(dai, sun4i_spdif_controls,
+ ARRAY_SIZE(sun4i_spdif_controls));
+
return 0;
}
@@ -512,6 +626,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
return -ENOMEM;
host->pdev = pdev;
+ spin_lock_init(&host->lock);
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 518bfb724a5b..0bea2162f68d 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -21,6 +21,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
#define SUN8I_SYSCLK_CTL 0x00c
#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
@@ -72,6 +73,12 @@
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8
+#define SUN8I_AIF1_VOL_CTRL1 0x050
+#define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL 8
+#define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL 0
+#define SUN8I_AIF1_VOL_CTRL3 0x058
+#define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL 8
+#define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL 0
#define SUN8I_AIF2_ADCDAT_CTRL 0x084
#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA 15
#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA 14
@@ -91,6 +98,12 @@
#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R 10
#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL 9
#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR 8
+#define SUN8I_AIF2_VOL_CTRL1 0x090
+#define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL 8
+#define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL 0
+#define SUN8I_AIF2_VOL_CTRL2 0x098
+#define SUN8I_AIF2_VOL_CTRL2_DACL_VOL 8
+#define SUN8I_AIF2_VOL_CTRL2_DACR_VOL 0
#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1 (0x0 << 0)
#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2 (0x1 << 0)
#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK (0x2 << 0)
@@ -102,8 +115,14 @@
#define SUN8I_ADC_DIG_CTRL_ENAD 15
#define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2
#define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1
+#define SUN8I_ADC_VOL_CTRL 0x104
+#define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8
+#define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0
#define SUN8I_DAC_DIG_CTRL 0x120
#define SUN8I_DAC_DIG_CTRL_ENDA 15
+#define SUN8I_DAC_VOL_CTRL 0x124
+#define SUN8I_DAC_VOL_CTRL_DACL_VOL 8
+#define SUN8I_DAC_VOL_CTRL_DACR_VOL 0
#define SUN8I_DAC_MXR_SRC 0x130
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
@@ -696,6 +715,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = {
},
};
+static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
+
+static const struct snd_kcontrol_new sun8i_codec_controls[] = {
+ SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume",
+ SUN8I_AIF1_VOL_CTRL1,
+ SUN8I_AIF1_VOL_CTRL1_AD0L_VOL,
+ SUN8I_AIF1_VOL_CTRL1_AD0R_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+ SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume",
+ SUN8I_AIF1_VOL_CTRL3,
+ SUN8I_AIF1_VOL_CTRL3_DA0L_VOL,
+ SUN8I_AIF1_VOL_CTRL3_DA0R_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+ SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
+ SUN8I_AIF2_VOL_CTRL1,
+ SUN8I_AIF2_VOL_CTRL1_ADCL_VOL,
+ SUN8I_AIF2_VOL_CTRL1_ADCR_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+ SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
+ SUN8I_AIF2_VOL_CTRL2,
+ SUN8I_AIF2_VOL_CTRL2_DACL_VOL,
+ SUN8I_AIF2_VOL_CTRL2_DACR_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+ SOC_DOUBLE_TLV("ADC Capture Volume",
+ SUN8I_ADC_VOL_CTRL,
+ SUN8I_ADC_VOL_CTRL_ADCL_VOL,
+ SUN8I_ADC_VOL_CTRL_ADCR_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+ SOC_DOUBLE_TLV("DAC Playback Volume",
+ SUN8I_DAC_VOL_CTRL,
+ SUN8I_DAC_VOL_CTRL_DACL_VOL,
+ SUN8I_DAC_VOL_CTRL_DACR_VOL,
+ 0xc0, 0, sun8i_codec_vol_scale),
+};
+
static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1215,6 +1269,8 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
}
static const struct snd_soc_component_driver sun8i_soc_component = {
+ .controls = sun8i_codec_controls,
+ .num_controls = ARRAY_SIZE(sun8i_codec_controls),
.dapm_widgets = sun8i_codec_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
.dapm_routes = sun8i_codec_dapm_routes,