summaryrefslogtreecommitdiff
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/ab8500.c208
-rw-r--r--sound/soc/codecs/ab8500.h3
-rw-r--r--sound/soc/codecs/cg29xx.c6
3 files changed, 173 insertions, 44 deletions
diff --git a/sound/soc/codecs/ab8500.c b/sound/soc/codecs/ab8500.c
index 2d2142082a7..b9685518ae1 100644
--- a/sound/soc/codecs/ab8500.c
+++ b/sound/soc/codecs/ab8500.c
@@ -1059,6 +1059,7 @@ static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1);
static const char *enum_ena_dis[] = {"Enabled", "Disabled"};
static const char *enum_dis_ena[] = {"Disabled", "Enabled"};
+
static SOC_ENUM_SINGLE_DECL(soc_enum_hshpen,
REG_ANACONF1, REG_ANACONF1_HSHPEN, enum_dis_ena);
static SOC_ENUM_SINGLE_DECL(soc_enum_hslowpow,
@@ -1145,7 +1146,14 @@ static const char *enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"};
static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed,
REG_HSRDIGGAIN, REG_HSRDIGGAIN_FADESPEED, enum_fadespeed);
-/* XXX move to DAPM */
+static SOC_ENUM_SINGLE_DECL(soc_enum_mastgen,
+ REG_DIGIFCONF1, REG_DIGIFCONF1_ENMASTGEN, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk0,
+ REG_DIGIFCONF1, REG_DIGIFCONF1_ENFSBITCLK0, enum_dis_ena);
+static SOC_ENUM_SINGLE_DECL(soc_enum_fsbitclk1,
+ REG_DIGIFCONF1, REG_DIGIFCONF1_ENFSBITCLK1, enum_dis_ena);
+
+/* TODO: move to DAPM */
static SOC_ENUM_SINGLE_DECL(soc_enum_enfirsids,
REG_SIDFIRCONF, REG_SIDFIRCONF_ENFIRSIDS, enum_dis_ena);
static SOC_ENUM_SINGLE_DECL(soc_enum_parlhf,
@@ -1220,7 +1228,7 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
REG_PWMGENCONFX_PWMVIBXDUTCYC,
REG_PWMGENCONFX_PWMVIBXDUTCYC_MAX, NORMAL),
- /* XXX move to DAPM */
+ /* TODO: move to DAPM */
SOC_ENUM("Sidetone Playback Switch", soc_enum_enfirsids),
SOC_ENUM("IHF L and R Bridge Playback Route", soc_enum_parlhf),
SOC_ENUM("Vibra 1 and 2 Bridge Playback Route", soc_enum_parlvib),
@@ -1280,6 +1288,10 @@ static struct snd_kcontrol_new ab8500_snd_controls[] = {
REG_DIGLINHSLGAIN, REG_DIGLINHSRGAIN,
REG_DIGLINHSXGAIN_LINTOHSXGAIN,
REG_DIGLINHSXGAIN_LINTOHSXGAIN_MAX, INVERT, lin2hs_gain_tlv),
+
+ 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),
};
static int ab8500_add_widgets(struct snd_soc_codec *codec)
@@ -1305,6 +1317,63 @@ static int ab8500_add_widgets(struct snd_soc_codec *codec)
return 0;
}
+int ab8500_set_word_length(struct snd_soc_dai *dai, unsigned int wl)
+{
+ unsigned int clear_mask;
+ unsigned int set_mask = 0;
+ struct snd_soc_codec *codec = dai->codec;
+
+ clear_mask = BMASK(REG_DIGIFCONF2_IF0WL0) | BMASK(REG_DIGIFCONF2_IF0WL1);
+
+ switch (wl) {
+ case 16:
+ break;
+ case 20:
+ set_mask |= BMASK(REG_DIGIFCONF2_IF0WL0);
+ break;
+ case 24:
+ set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1);
+ 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_update_audio_reg(codec, REG_DIGIFCONF2, clear_mask, set_mask);
+
+ return 0;
+}
+
+int ab8500_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay)
+{
+ unsigned int clear_mask;
+ unsigned int set_mask = 0;
+ struct snd_soc_codec *codec = dai->codec;
+
+ clear_mask = BMASK(REG_DIGIFCONF2_IF0DEL);
+
+ switch (delay) {
+ case 0:
+ break;
+ case 1:
+ set_mask |= BMASK(REG_DIGIFCONF2_IF0DEL);
+ break;
+ default:
+ pr_err("%s: Unsupported bit-delay (0x%x)!\n", __func__, delay);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Bit-delay: %d bits.\n", __func__, delay);
+ ab8500_update_audio_reg(codec, REG_DIGIFCONF2, clear_mask, set_mask);
+
+ return 0;
+}
+
static int ab8500_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
{
@@ -1388,16 +1457,16 @@ static int set_dai_clock_gate(struct snd_soc_codec *codec, unsigned int fmt)
clear_mask = BMASK(REG_DIGIFCONF1_ENMASTGEN) |
BMASK(REG_DIGIFCONF1_ENFSBITCLK0);
- set_mask = 0;
+
+ set_mask = BMASK(REG_DIGIFCONF1_ENMASTGEN);
switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
case SND_SOC_DAIFMT_CONT: /* continuous clock */
- pr_info("- Clock is not gated\n");
- set_mask |= BMASK(REG_DIGIFCONF1_ENMASTGEN);
+ pr_info("- Clock is continous.\n");
set_mask |= BMASK(REG_DIGIFCONF1_ENFSBITCLK0);
break;
case SND_SOC_DAIFMT_GATED: /* clock is gated */
- pr_info("- Clock IS gated\n");
+ pr_info("- Clock is gated.\n");
break;
default:
pr_err("Unsupporter clock mask 0x%x\n",
@@ -1435,22 +1504,26 @@ static int ab8500_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
/* Setting data transfer format */
- clear_mask = REG_MASK_ALL;
+ 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");
set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT1);
- set_mask |= BMASK(REG_DIGIFCONF2_IF0DEL);
- /* 32 bit */
- set_mask |= BMASK(REG_DIGIFCONF2_IF0WL1) |
- BMASK(REG_DIGIFCONF2_IF0WL0);
+ /* 32 bit, 0 delay */
+ ab8500_set_word_length(dai, 32);
+ ab8500_set_bit_delay(dai, 0);
+
break;
case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
pr_info("- FORMAT DSP A\n");
- set_mask |= BMASK(REG_DIGIFCONF2_IF0FORMAT0);
+ 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");
@@ -1496,9 +1569,8 @@ static int ab8500_set_dai_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
{
- int data;
struct snd_soc_codec *codec = dai->codec;
- unsigned int clear_mask;
+ unsigned int set_mask, clear_mask, slots_active;
/* Only 16 bit slot width is supported at the moment in TDM mode */
if (slot_width != 16) {
@@ -1507,48 +1579,98 @@ static int ab8500_set_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- /* Set the TDM clocking according to slot count */
+ /* Setup TDM clocking according to slot count */
+ pr_debug("%s: Slots, total: %d\n", __func__, slots);
+ clear_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) |
+ BMASK(REG_DIGIFCONF1_IF0BITCLKOS1);
switch (slots) {
case 2:
- data = REG_MASK_NONE;
+ set_mask = REG_MASK_NONE;
break;
case 4:
- data = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0);
+ set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0);
break;
case 8:
- data = BMASK(REG_DIGIFCONF1_IF0BITCLKOS1);
+ set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS1);
break;
case 16:
- data = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) |
+ set_mask = BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) |
BMASK(REG_DIGIFCONF1_IF0BITCLKOS1);
break;
default:
- pr_err("%s: Unsupported slots %d.\n", __func__, slots);
+ pr_err("%s: Unsupported number of slots (%d)!\n", __func__, slots);
return -EINVAL;
}
+ ab8500_update_audio_reg(codec, REG_DIGIFCONF1, clear_mask, set_mask);
- ab8500_update_audio_reg(codec, REG_DIGIFCONF1,
- BMASK(REG_DIGIFCONF1_IF0BITCLKOS0) |
- BMASK(REG_DIGIFCONF1_IF0BITCLKOS1),
- data);
-
- /* XXX Make slot configuration as a control */
-
+ /* Setup TDM DA according to active tx slots */
clear_mask = REG_DASLOTCONFX_SLTODAX_MASK;
+ slots_active = hweight32(tx_mask);
+ pr_debug("%s: Slots, active, TX: %d\n", __func__, slots_active);
+ switch (slots_active) {
+ case 0:
+ break;
+ case 1:
+ /* Slot 9 -> DA_IN1 & DA_IN3 */
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF1, clear_mask, 9);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF3, clear_mask, 9);
+ break;
+ case 2:
+ /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF1, clear_mask, 9);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF3, clear_mask, 9);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF2, clear_mask, 11);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF4, clear_mask, 11);
- /* DA_IN1/3/5 receives slot 9, DA_IN2/4/6 receives slot 11 */
- ab8500_update_audio_reg(codec, REG_DASLOTCONF1, clear_mask, 9);
- ab8500_update_audio_reg(codec, REG_DASLOTCONF2, clear_mask, 11);
- ab8500_update_audio_reg(codec, REG_DASLOTCONF3, clear_mask, 9);
- ab8500_update_audio_reg(codec, REG_DASLOTCONF4, clear_mask, 11);
- ab8500_update_audio_reg(codec, REG_DASLOTCONF5, clear_mask, 9);
- ab8500_update_audio_reg(codec, REG_DASLOTCONF6, clear_mask, 11);
+ break;
+ case 8:
+ /* Slot 8-15 -> DA_IN1-DA_IN8 */
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF1, clear_mask, 8);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF2, clear_mask, 9);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF3, clear_mask, 10);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF4, clear_mask, 11);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF5, clear_mask, 12);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF6, clear_mask, 13);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF7, clear_mask, 14);
+ ab8500_update_audio_reg(codec, REG_DASLOTCONF8, clear_mask, 15);
- /* AD_OUT3 transmits slots 0 & 1 */
- ab8500_update_audio_reg(codec, REG_ADSLOTSEL1,
+ break;
+ default:
+ pr_err("%s: Unsupported number of active TX-slots (%d)!\n", __func__, slots_active);
+ return -EINVAL;
+ }
+
+ /* Setup TDM AD according to active RX-slots */
+ slots_active = hweight32(rx_mask);
+ pr_debug("%s: Slots, active, RX: %d\n", __func__, slots_active);
+ switch (slots_active) {
+ case 0:
+ break;
+ case 1:
+ /* AD_OUT3 -> slot 0 & 1 */
+ ab8500_update_audio_reg(codec, REG_ADSLOTSEL1,
REG_MASK_ALL,
BMASK(REG_ADSLOTSELX_ODDX_1) |
BMASK(REG_ADSLOTSELX_EVENX_1));
+ break;
+ case 2:
+ /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+ ab8500_update_audio_reg(codec, REG_ADSLOTSEL1,
+ REG_MASK_ALL,
+ BMASK(REG_ADSLOTSELX_ODDX_0) |
+ BMASK(REG_ADSLOTSELX_EVENX_1));
+ break;
+ case 8:
+ /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+ ab8500_update_audio_reg(codec, REG_ADSLOTSEL1,
+ REG_MASK_ALL,
+ BMASK(REG_ADSLOTSELX_ODDX_0) |
+ BMASK(REG_ADSLOTSELX_EVENX_1));
+ break;
+ default:
+ pr_err("%s: Unsupported number of active RX-slots (%d)!\n", __func__, slots_active);
+ return -EINVAL;
+ }
return 0;
}
@@ -1560,7 +1682,7 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = {
.playback = {
.stream_name = "ab8500_0p",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = AB8500_SUPPORTED_RATE,
.formats = AB8500_SUPPORTED_FMT,
},
@@ -1583,7 +1705,7 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = {
.capture = {
.stream_name = "ab8500_0c",
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 8,
.rates = AB8500_SUPPORTED_RATE,
.formats = AB8500_SUPPORTED_FMT,
},
@@ -1720,12 +1842,16 @@ struct snd_soc_codec_driver ab8500_codec_drv = {
.reg_cache_default = ab8500_reg_cache,
};
-static int __devinit ab8500_codec_drv_probe(struct platform_device *pdev)
+static int ab8500_codec_drv_probe(struct platform_device *pdev)
{
int err;
+ struct ab8500_codec_dai_data *dai_data;
pr_debug("%s: Enter.\n", __func__);
+ platform_set_drvdata(pdev, dai_data);
+
+ pr_info("%s: Register codec.\n", __func__);
err = snd_soc_register_codec(&pdev->dev,
&ab8500_codec_drv,
ab8500_codec_dai,
@@ -1739,7 +1865,7 @@ static int __devinit ab8500_codec_drv_probe(struct platform_device *pdev)
return err;
}
-static int __devexit ab8500_codec_drv_remove(struct platform_device *pdev)
+static int ab8500_codec_drv_remove(struct platform_device *pdev)
{
pr_debug("%s Enter.\n", __func__);
@@ -1769,7 +1895,7 @@ static struct platform_driver ab8500_codec_platform_drv = {
.owner = THIS_MODULE,
},
.probe = ab8500_codec_drv_probe,
- .remove = __devexit_p(ab8500_codec_drv_remove),
+ .remove = ab8500_codec_drv_remove,
.suspend = ab8500_codec_drv_suspend,
.resume = ab8500_codec_drv_resume,
};
diff --git a/sound/soc/codecs/ab8500.h b/sound/soc/codecs/ab8500.h
index 415d73a87a5..ef3e4907878 100644
--- a/sound/soc/codecs/ab8500.h
+++ b/sound/soc/codecs/ab8500.h
@@ -22,6 +22,9 @@ extern struct snd_soc_codec_driver soc_codec_dev_ab8500;
#define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+int ab8500_set_word_length(struct snd_soc_dai *dai, unsigned int wl);
+int ab8500_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay);
+
/* AB8500 audio bank (0x0d) register definitions */
#define REG_POWERUP 0x00
diff --git a/sound/soc/codecs/cg29xx.c b/sound/soc/codecs/cg29xx.c
index 56b23be8e97..272f8f9287b 100644
--- a/sound/soc/codecs/cg29xx.c
+++ b/sound/soc/codecs/cg29xx.c
@@ -651,7 +651,7 @@ struct snd_soc_codec_driver cg29xx_codec_drv = {
.write = cg29xx_codec_write,
};
-static __devinit int cg29xx_codec_drv_probe(struct platform_device *pdev)
+static int cg29xx_codec_drv_probe(struct platform_device *pdev)
{
int ret;
struct cg29xx_codec_dai_data *dai_data;
@@ -714,7 +714,7 @@ static __devinit int cg29xx_codec_drv_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit cg29xx_codec_drv_remove(struct platform_device *pdev)
+static int cg29xx_codec_drv_remove(struct platform_device *pdev)
{
(void)cg2900_audio_close(&codec_private.session);
@@ -741,7 +741,7 @@ static struct platform_driver cg29xx_codec_platform_drv = {
.owner = THIS_MODULE,
},
.probe = cg29xx_codec_drv_probe,
- .remove = __devexit_p(cg29xx_codec_drv_remove),
+ .remove = cg29xx_codec_drv_remove,
.suspend = cg29xx_codec_drv_suspend,
.resume = cg29xx_codec_drv_resume,
};