summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-05-06 14:18:39 +0200
committerRobert Marklund <robert.marklund@stericsson.com>2011-10-05 11:19:22 +0200
commitc5864bac30dbaa3a0e81a3edda3ebad6b445cd21 (patch)
tree05e4a8fc7dc046676c46fa0e7cc5b92d016520d6 /sound
parent39ea25074b716b0b9383f551f9d4e311f2f227c8 (diff)
Ux500 ASoC: Support configuration of I2S interface 1
Added support for configuring the second I2S interface. This is needed for FM-radio. Change-Id: I1a8cd908f66db45b6031d15d33779236a1a55344 Signed-off-by: Ola Lilja <elilola@steludxu2785.(none)> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/19821 Tested-by: Ola LILJA2 <ola.o.lilja@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Reviewed-by: Roger NILSSON1 <roger.xr.nilsson@stericsson.com> Conflicts: sound/soc/codecs/ab8500_audio.c
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/ab8500_audio.c322
-rw-r--r--sound/soc/codecs/ab8500_audio.h18
-rw-r--r--sound/soc/ux500/ux500_ab8500.c26
3 files changed, 263 insertions, 103 deletions
diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c
index 49c90a0982b..47930a7ef53 100644
--- a/sound/soc/codecs/ab8500_audio.c
+++ b/sound/soc/codecs/ab8500_audio.c
@@ -1145,6 +1145,8 @@ static const char *enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"};
static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed,
REG_HSRDIGGAIN, REG_HSRDIGGAIN_FADESPEED, enum_fadespeed);
+/* Digital interface controls */
+
static SOC_ENUM_SINGLE_DECL(soc_enum_mastgen,
REG_DIGIFCONF1, REG_DIGIFCONF1_ENMASTGEN, enum_dis_ena);
static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk0,
@@ -1152,6 +1154,23 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk0,
static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk1,
REG_DIGIFCONF1, REG_DIGIFCONF1_ENFSBITCLK1, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad1loop,
+ REG_DASLOTCONF1, REG_DASLOTCONF1_DAI7TOADO1, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad2loop,
+ REG_DASLOTCONF2, REG_DASLOTCONF2_DAI8TOADO2, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad3loop,
+ REG_DASLOTCONF3, REG_DASLOTCONF3_DAI7TOADO3, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad4loop,
+ REG_DASLOTCONF4, REG_DASLOTCONF4_DAI8TOADO4, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad5loop,
+ REG_DASLOTCONF5, REG_DASLOTCONF5_DAI7TOADO5, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad6loop,
+ REG_DASLOTCONF6, REG_DASLOTCONF6_DAI8TOADO6, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad7loop,
+ REG_DASLOTCONF7, REG_DASLOTCONF7_DAI8TOADO7, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_ad8loop,
+ REG_DASLOTCONF8, REG_DASLOTCONF8_DAI7TOADO8, enum_dis_ena);
+
/* TODO: move to DAPM */
static SOC_ENUM_SINGLE_DECL(soc_enum_enfirsids,
REG_SIDFIRCONF, REG_SIDFIRCONF_ENFIRSIDS, enum_dis_ena);
@@ -1196,7 +1215,7 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
SOC_ENUM("IHF FIR Bypass Playback Switch", soc_enum_fir01byp),
SOC_ENUM("Vibra FIR Bypass Playback Switch", soc_enum_fir23byp),
- /* XXX Cannot be changed on the fly with digital channel enabled. */
+ /* TODO: Cannot be changed on the fly with digital channel enabled. */
SOC_ENUM("IHF High Volume Playback Switch", soc_enum_highvol01),
SOC_ENUM("Vibra High Volume Playback Switch", soc_enum_highvol23),
@@ -1213,7 +1232,7 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
SOC_ENUM("Headset Source Playback Route", soc_enum_da2hslr),
- /* XXX Cannot be changed on the fly with digital channel enabled. */
+ /* TODO: Cannot be changed on the fly with digital channel enabled. */
SOC_ENUM("Headset Filter Playback Switch", soc_enum_hsesinc),
SOC_ENUM("Digital Gain Fade Speed Switch", soc_enum_fadespeed),
@@ -1288,31 +1307,134 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
REG_DIGLINHSXGAIN_LINTOHSXGAIN,
REG_DIGLINHSXGAIN_LINTOHSXGAIN_MAX, INVERT, lin2hs_gain_tlv),
+ /* Digital Interface controls */
SOC_ENUM("Digital Interface Master Generator Switch", soc_enum_mastgen),
SOC_ENUM("Digital Interface 0 Bit-clock Switch", soc_enum_fsbitclk0),
SOC_ENUM("Digital Interface 1 Bit-clock Switch", soc_enum_fsbitclk1),
+ SOC_ENUM("Digital Interface AD 1 Loopback Switch", soc_enum_ad1loop),
+ SOC_ENUM("Digital Interface AD 2 Loopback Switch", soc_enum_ad2loop),
+ SOC_ENUM("Digital Interface AD 3 Loopback Switch", soc_enum_ad3loop),
+ SOC_ENUM("Digital Interface AD 4 Loopback Switch", soc_enum_ad4loop),
+ SOC_ENUM("Digital Interface AD 5 Loopback Switch", soc_enum_ad5loop),
+ SOC_ENUM("Digital Interface AD 6 Loopback Switch", soc_enum_ad6loop),
+ SOC_ENUM("Digital Interface AD 7 Loopback Switch", soc_enum_ad7loop),
+ SOC_ENUM("Digital Interface AD 8 Loopback Switch", soc_enum_ad8loop),
};
-static int ab8500_add_widgets(struct snd_soc_codec *codec)
+static int ab8500_codec_set_format_if1(struct snd_soc_codec *codec, unsigned int fmt)
{
- int ret;
+ unsigned int clear_mask, set_mask;
- ret = snd_soc_dapm_new_controls(&codec->dapm, ab8500_dapm_widgets,
- ARRAY_SIZE(ab8500_dapm_widgets));
- if (ret < 0) {
- pr_err("%s: Failed to create DAPM controls (%d).\n",
- __func__, ret);
- return ret;
+ /* Master or slave */
+
+ clear_mask = BMASK(REG_DIGIFCONF3_IF1MASTER);
+ set_mask = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
+ pr_debug("%s: IF1 Master-mode: AB8500 master.\n", __func__);
+ set_mask |= BMASK(REG_DIGIFCONF3_IF1MASTER);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
+ pr_debug("%s: IF1 Master-mode: AB8500 slave.\n", __func__);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
+ case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+ pr_err("%s: ERROR: The device is either a master or a slave.\n",
+ __func__);
+ default:
+ pr_err("%s: ERROR: Unsupporter master mask 0x%x\n",
+ __func__,
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
}
- ret = snd_soc_dapm_add_routes(&codec->dapm, intercon,
- ARRAY_SIZE(intercon));
- if (ret < 0) {
- pr_err("%s: Failed to add DAPM routes (%d).\n",
- __func__, ret);
- return ret;
+ ab8500_codec_update_reg_audio(codec,
+ REG_DIGIFCONF3,
+ BMASK(REG_DIGIFCONF3_IF1MASTER),
+ BMASK(REG_DIGIFCONF3_IF1MASTER));
+
+ /* I2S or TDM */
+
+ clear_mask = BMASK(REG_DIGIFCONF4_FSYNC1P) |
+ BMASK(REG_DIGIFCONF4_BITCLK1P) |
+ BMASK(REG_DIGIFCONF4_IF1FORMAT1) |
+ BMASK(REG_DIGIFCONF4_IF1FORMAT0);
+ set_mask = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S: /* I2S mode */
+ pr_debug("%s: IF1 Protocol: I2S\n", __func__);
+ set_mask |= BMASK(REG_DIGIFCONF4_IF1FORMAT1);
+ break;
+ case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+ pr_debug("%s: IF1 Protocol: DSP B (TDM)\n", __func__);
+ set_mask |= BMASK(REG_DIGIFCONF4_IF1FORMAT0);
+ break;
+ default:
+ pr_err("%s: ERROR: Unsupported format (0x%x)!\n",
+ __func__,
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask);
+
+ return 0;
+}
+
+static int ab8500_codec_set_word_length_if1(struct snd_soc_codec *codec, unsigned int wl)
+{
+ unsigned int clear_mask, set_mask;
+
+ clear_mask = BMASK(REG_DIGIFCONF4_IF1WL1) | BMASK(REG_DIGIFCONF4_IF1WL0);
+ set_mask = 0;
+
+ switch (wl) {
+ case 16:
+ break;
+ case 20:
+ set_mask |= BMASK(REG_DIGIFCONF4_IF1WL0);
+ break;
+ case 24:
+ set_mask |= BMASK(REG_DIGIFCONF4_IF1WL1);
+ break;
+ case 32:
+ set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1) |
+ BMASK(REG_DIGIFCONF2_IF0WL0);
+ break;
+ default:
+ pr_err("%s: Unsupporter word-length 0x%x\n", __func__, wl);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Word-length: %d bits.\n", __func__, wl);
+ ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask);
+
+ return 0;
+}
+
+static int ab8500_codec_set_bit_delay_if1(struct snd_soc_codec *codec, unsigned int delay)
+{
+ unsigned int clear_mask, set_mask;
+
+ clear_mask = BMASK(REG_DIGIFCONF4_IF1DEL);
+ set_mask = 0;
+
+ switch (delay) {
+ case 0:
+ break;
+ case 1:
+ set_mask |= BMASK(REG_DIGIFCONF4_IF1DEL);
+ break;
+ default:
+ pr_err("%s: ERROR: Unsupported bit-delay (0x%x)!\n", __func__, delay);
+ return -EINVAL;
}
+ pr_debug("%s: IF1 Bit-delay: %d bits.\n", __func__, delay);
+ ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF4, clear_mask, set_mask);
+
return 0;
}
@@ -1320,11 +1442,11 @@ static int ab8500_add_widgets(struct snd_soc_codec *codec)
int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl)
{
- unsigned int clear_mask;
- unsigned int set_mask = 0;
+ unsigned int clear_mask, set_mask;
struct snd_soc_codec *codec = dai->codec;
clear_mask = BMASK(REG_DIGIFCONF2_IF0WL0) | BMASK(REG_DIGIFCONF2_IF0WL1);
+ set_mask = 0;
switch (wl) {
case 16:
@@ -1344,7 +1466,7 @@ int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl)
return -EINVAL;
}
- pr_debug("%s: Word-length: %d bits.\n", __func__, wl);
+ pr_debug("%s: IF0 Word-length: %d bits.\n", __func__, wl);
ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF2, clear_mask, set_mask);
return 0;
@@ -1352,11 +1474,11 @@ int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl)
int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay)
{
- unsigned int clear_mask;
- unsigned int set_mask = 0;
+ unsigned int clear_mask, set_mask;
struct snd_soc_codec *codec = dai->codec;
clear_mask = BMASK(REG_DIGIFCONF2_IF0DEL);
+ set_mask = 0;
switch (delay) {
case 0:
@@ -1365,17 +1487,42 @@ int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay)
set_mask |= BMASK(REG_DIGIFCONF2_IF0DEL);
break;
default:
- pr_err("%s: Unsupported bit-delay (0x%x)!\n", __func__, delay);
+ pr_err("%s: ERROR: Unsupported bit-delay (0x%x)!\n", __func__, delay);
return -EINVAL;
}
- pr_debug("%s: Bit-delay: %d bits.\n", __func__, delay);
+ pr_debug("%s: IF0 Bit-delay: %d bits.\n", __func__, delay);
ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF2, clear_mask, set_mask);
return 0;
}
-static int ab8500_add_widgets(struct snd_soc_codec *codec)
+int ab8500_audio_setup_if1(struct snd_soc_codec *codec,
+ unsigned int fmt,
+ unsigned int wl,
+ unsigned int delay)
+{
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ ret = ab8500_codec_set_format_if1(codec, fmt);
+ if (ret)
+ return -1;
+
+ ret = ab8500_codec_set_bit_delay_if1(codec, delay);
+ if (ret)
+ return -1;
+
+
+ ret = ab8500_codec_set_word_length_if1(codec, wl);
+ if (ret)
+ return -1;
+
+ return 0;
+}
+
+static int ab8500_codec_add_widgets(struct snd_soc_codec *codec)
{
int ret;
@@ -1437,42 +1584,6 @@ static int ab8500_codec_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
-/* Sets Master/Slave relations according format mask */
-static int ab8500_codec_set_dai_relationship(struct snd_soc_codec *codec,
- unsigned int fmt)
-{
- unsigned int clear_mask;
- unsigned int set_mask;
-
- clear_mask = BMASK(REG_DIGIFCONF3_IF1DATOIF0AD) |
- BMASK(REG_DIGIFCONF3_IF1CLKTOIF0CLK) |
- BMASK(REG_DIGIFCONF3_IF0BFIFOEN) |
- BMASK(REG_DIGIFCONF3_IF0MASTER);
- set_mask = 0;
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
- pr_info("- Codec is a master\n");
- set_mask |= BMASK(REG_DIGIFCONF3_IF0MASTER);
- break;
- case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
- pr_info("- Codec is a slave\n");
- break;
- case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
- case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
- pr_err("The device is either a master or a slave.\n");
- default:
- pr_err("Unsupporter master mask 0x%x\n",
- (fmt & SND_SOC_DAIFMT_MASTER_MASK));
- return -EINVAL;
- break;
- }
-
- ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF3, clear_mask, set_mask);
-
- return 0;
-}
-
/* Gates clocking according format mask */
static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec, unsigned int fmt)
{
@@ -1486,17 +1597,17 @@ static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec, unsigned
switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
case SND_SOC_DAIFMT_CONT: /* continuous clock */
- pr_info("- Clock is continous.\n");
+ pr_debug("%s: IF0 Clock is continous.\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF1_ENFSBITCLK0);
break;
case SND_SOC_DAIFMT_GATED: /* clock is gated */
- pr_info("- Clock is gated.\n");
+ pr_debug("%s: IF0 Clock is gated.\n", __func__);
break;
default:
- pr_err("Unsupporter clock mask 0x%x\n",
- (fmt & SND_SOC_DAIFMT_CLOCK_MASK));
+ pr_err("%s: ERROR: Unsupporter clock mask (0x%x)!\n",
+ __func__,
+ fmt & SND_SOC_DAIFMT_CLOCK_MASK);
return -EINVAL;
- break;
}
ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF1, clear_mask, set_mask);
@@ -1511,33 +1622,53 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct snd_soc_codec *codec = dai->codec;
int err;
- pr_debug("%s: fmt = 0x%x\n", __func__, fmt);
+ pr_debug("%s: Enter (fmt = 0x%x)\n", __func__, fmt);
- /* Set Master/Slave */
- err = ab8500_codec_set_dai_relationship(codec, fmt);
- if (err) {
- pr_err("%s: Failed to set master/slave (%d).\n", __func__, err);
- return err;
+ clear_mask = BMASK(REG_DIGIFCONF3_IF1DATOIF0AD) |
+ BMASK(REG_DIGIFCONF3_IF1CLKTOIF0CLK) |
+ BMASK(REG_DIGIFCONF3_IF0BFIFOEN) |
+ BMASK(REG_DIGIFCONF3_IF0MASTER);
+ set_mask = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
+ pr_debug("%s: IF0 Master-mode: AB8500 master.\n", __func__);
+ set_mask |= BMASK(REG_DIGIFCONF3_IF0MASTER);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
+ pr_debug("%s: IF0 Master-mode: AB8500 slave.\n", __func__);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
+ case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+ pr_err("%s: ERROR: The device is either a master or a slave.\n");
+ default:
+ pr_err("%s: ERROR: Unsupporter master mask 0x%x\n",
+ __func__,
+ (fmt & SND_SOC_DAIFMT_MASTER_MASK));
+ return -EINVAL;
+ break;
}
- /* Set clock enable/disable */
+ ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF3, clear_mask, set_mask);
+
+ /* Set clock gating */
err = ab8500_codec_set_dai_clock_gate(codec, fmt);
if (err) {
- pr_err("%s: Failed to set clock gate (%d).\n", __func__, err);
+ pr_err("%s: ERRROR: Failed to set clock gate (%d).\n", __func__, err);
return err;
}
/* Setting data transfer format */
+
clear_mask = BMASK(REG_DIGIFCONF2_IF0FORMAT0) |
BMASK(REG_DIGIFCONF2_IF0FORMAT1) |
BMASK(REG_DIGIFCONF2_FSYNC0P) |
BMASK(REG_DIGIFCONF2_BITCLK0P);
-
set_mask = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: /* I2S mode */
- pr_info("- FORMAT I2S\n");
+ pr_debug("%s: IF0 Protocol: I2S\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT1);
/* 32 bit, 0 delay */
@@ -1546,39 +1677,40 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
- pr_info("- FORMAT DSP A\n");
+ pr_debug("%s: IF0 Protocol: DSP A (TDM)\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT1);
break;
case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
- pr_info("- FORMAT DSP B\n");
+ pr_debug("%s: IF0 Protocol: DSP B (TDM)\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT0);
break;
default:
- pr_err("Unsupporter format 0x%x\n",
- (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
+ pr_err("%s: ERROR: Unsupporter format (0x%x)!\n",
+ __func__,
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
- break;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
- pr_info("- Normal bit clock, normal frame\n");
+ pr_debug("%s: IF0: Normal bit clock, normal frame\n", __func__);
break;
case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
- pr_info("- Normal bit clock, inverted frame\n");
+ pr_debug("%s: IF0: Normal bit clock, inverted frame\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_FSYNC0P);
break;
case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
- pr_info("- inverted bit clock, normal frame\n");
+ pr_debug("%s: IF0: Inverted bit clock, normal frame\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_BITCLK0P);
break;
case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
- pr_info("- inverted bit clock, inverted frame\n");
+ pr_debug("%s: IF0: Inverted bit clock, inverted frame\n", __func__);
set_mask |= BMASK(REG_DIGIFCONF2_FSYNC0P);
set_mask |= BMASK(REG_DIGIFCONF2_BITCLK0P);
break;
default:
- pr_err("Unsupported INV mask 0x%x\n",
+ pr_err("%s: ERROR: Unsupported INV mask 0x%x\n",
+ __func__,
(fmt & SND_SOC_DAIFMT_INV_MASK));
return -EINVAL;
break;
@@ -1598,7 +1730,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
/* Only 16 bit slot width is supported at the moment in TDM mode */
if (slot_width != 16) {
- pr_err("%s: Unsupported slot_width %d.\n",
+ pr_err("%s: ERROR: Unsupported slot_width %d.\n",
__func__, slot_width);
return -EINVAL;
}
@@ -1622,7 +1754,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
BMASK(REG_DIGIFCONF1_IF0BITCLKOS1);
break;
default:
- pr_err("%s: Unsupported number of slots (%d)!\n", __func__, slots);
+ pr_err("%s: ERROR: Unsupported number of slots (%d)!\n", __func__, slots);
return -EINVAL;
}
ab8500_codec_update_reg_audio(codec, REG_DIGIFCONF1, clear_mask, set_mask);
@@ -1648,15 +1780,15 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
break;
case 8:
- /* Slot 8-15 -> DA_IN1-DA_IN8 */
+ /* Slot 8-13 -> DA_IN1-DA_IN6, Slot 24-25 -> DA_IN7-DA_IN8 */
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF1, clear_mask, 8);
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF2, clear_mask, 9);
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF3, clear_mask, 10);
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF4, clear_mask, 11);
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF5, clear_mask, 12);
ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF6, clear_mask, 13);
- ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF7, clear_mask, 14);
- ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF8, clear_mask, 15);
+ ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF7, clear_mask, 24);
+ ab8500_codec_update_reg_audio(codec, REG_DASLOTCONF8, clear_mask, 25);
break;
default:
@@ -1690,6 +1822,14 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
REG_MASK_ALL,
BMASK(REG_ADSLOTSELX_ODDX_0) |
BMASK(REG_ADSLOTSELX_EVENX_1));
+
+ /* AD_OUT5 -> slot 6, AD_OUT6 -> slot 7 */
+ ab8500_codec_update_reg_audio(codec, REG_ADSLOTSEL4,
+ REG_MASK_ALL,
+ BMASK(REG_ADSLOTSELX_ODDX_0) |
+ BMASK(REG_ADSLOTSELX_ODDX_2) |
+ BMASK(REG_ADSLOTSELX_EVENX_2));
+
break;
default:
pr_err("%s: Unsupported number of active RX-slots (%d)!\n", __func__, slots_active);
@@ -1822,7 +1962,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
return ret;
}
- ret = ab8500_add_widgets(codec);
+ ret = ab8500_codec_add_widgets(codec);
if (ret < 0) {
pr_err("%s: Failed add widgets (%d).\n", __func__, ret);
return ret;
diff --git a/sound/soc/codecs/ab8500_audio.h b/sound/soc/codecs/ab8500_audio.h
index 66c481cf411..6946e25bc4d 100644
--- a/sound/soc/codecs/ab8500_audio.h
+++ b/sound/soc/codecs/ab8500_audio.h
@@ -15,16 +15,19 @@
#ifndef AB8500_CODEC_REGISTERS_H
#define AB8500_CODEC_REGISTERS_H
-extern struct snd_soc_dai_driver ab8500_codec_dai[];
-extern struct snd_soc_codec_driver soc_codec_dev_ab8500;
-
#define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
-
#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+extern struct snd_soc_dai_driver ab8500_codec_dai[];
+extern struct snd_soc_codec_driver soc_codec_dev_ab8500;
+
/* Extended interface for codec-driver */
int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl);
int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay);
+int ab8500_audio_setup_if1(struct snd_soc_codec *codec,
+ unsigned int fmt,
+ unsigned int wl,
+ unsigned int delay);
/* AB8500 audio bank (0x0d) register definitions */
@@ -322,6 +325,13 @@ int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay);
#define REG_DIGIFCONF3_IF0BFIFOEN 0
/* REG_DIGIFCONF4 */
+#define REG_DIGIFCONF4_FSYNC1P 6
+#define REG_DIGIFCONF4_BITCLK1P 5
+#define REG_DIGIFCONF4_IF1DEL 4
+#define REG_DIGIFCONF4_IF1FORMAT1 3
+#define REG_DIGIFCONF4_IF1FORMAT0 2
+#define REG_DIGIFCONF4_IF1WL1 1
+#define REG_DIGIFCONF4_IF1WL0 0
/* REG_ADSLOTSELX */
#define REG_ADSLOTSELX_ODDX_3 7
diff --git a/sound/soc/ux500/ux500_ab8500.c b/sound/soc/ux500/ux500_ab8500.c
index f4cdd36f4d3..d2c0493aa5e 100644
--- a/sound/soc/ux500/ux500_ab8500.c
+++ b/sound/soc/ux500/ux500_ab8500.c
@@ -147,14 +147,13 @@ void ux500_ab8500_shutdown(struct snd_pcm_substream *substream)
rx_slots = DEF_RX_SLOTS;
}
-int ux500_ab8500_hw_params(
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+int ux500_ab8500_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int fmt;
+ unsigned int fmt, fmt_if1;
int channels, ret = 0, slots, slot_width, driver_mode;
bool streamIsPlayback;
@@ -238,14 +237,25 @@ int ux500_ab8500_hw_params(
pr_debug("%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n",
__func__, tx_slots, rx_slots);
- ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots,
- slots, slot_width);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots, slot_width);
+ if (ret)
+ return ret;
pr_debug("%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n",
__func__, tx_slots, rx_slots);
- ret += snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, slot_width);
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, slot_width);
+ if (ret)
+ return ret;
- return ret;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: Setup IF1 for FM-radio.\n", __func__);
+ fmt_if1 = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_I2S;
+ ret = ab8500_audio_setup_if1(codec_dai->codec, fmt_if1, 16, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int regulator_event(struct snd_soc_dapm_widget *w,