diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/arizona.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/cs4265.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/da732x.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/max98090.c | 115 | ||||
-rw-r--r-- | sound/soc/codecs/max98090.h | 3 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/rt286.c | 7 | ||||
-rw-r--r-- | sound/soc/codecs/rt5640.c | 1 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/ssm2602.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/sta529.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic31xx.c | 51 |
12 files changed, 180 insertions, 41 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index bd41ee4da078..2c71f16bd661 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, else rates = &arizona_48k_bclk_rates[0]; + wl = snd_pcm_format_width(params_format(params)); + if (tdm_slots) { arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", tdm_slots, tdm_width); @@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, channels = tdm_slots; } else { bclk_target = snd_soc_params_to_bclk(params); + tdm_width = wl; } if (chan_limit && chan_limit < channels) { @@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", rates[bclk], rates[bclk] / lrclk); - wl = snd_pcm_format_width(params_format(params)); - frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; + frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width; reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index a20b30ca52c0..69a85164357c 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -282,10 +282,10 @@ static const struct cs4265_clk_para clk_map_table[] = { /*64k*/ {8192000, 64000, 1, 0}, - {1228800, 64000, 1, 1}, - {1693440, 64000, 1, 2}, - {2457600, 64000, 1, 3}, - {3276800, 64000, 1, 4}, + {12288000, 64000, 1, 1}, + {16934400, 64000, 1, 2}, + {24576000, 64000, 1, 3}, + {32768000, 64000, 1, 4}, /* 88.2k */ {11289600, 88200, 1, 0}, @@ -435,10 +435,10 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); if (index >= 0) { snd_soc_update_bits(codec, CS4265_ADC_CTL, - CS4265_ADC_FM, clk_map_table[index].fm_mode); + CS4265_ADC_FM, clk_map_table[index].fm_mode << 6); snd_soc_update_bits(codec, CS4265_MCLK_FREQ, CS4265_MCLK_FREQ_MASK, - clk_map_table[index].mclkdiv); + clk_map_table[index].mclkdiv << 4); } else { dev_err(codec->dev, "can't get correct mclk\n"); @@ -458,12 +458,12 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, if (params_width(params) == 16) { snd_soc_update_bits(codec, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (1 << 5)); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 7)); } else { snd_soc_update_bits(codec, CS4265_DAC_CTL, CS4265_DAC_CTL_DIF, (3 << 5)); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 7)); } break; @@ -472,7 +472,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, CS4265_DAC_CTL_DIF, 0); snd_soc_update_bits(codec, CS4265_ADC_CTL, CS4265_ADC_DIF, 0); - snd_soc_update_bits(codec, CS4265_ADC_CTL, + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, CS4265_SPDIF_CTL2_DIF, (1 << 6)); break; diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index 1dceafeec415..f586cbd30b77 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h @@ -11,7 +11,7 @@ */ #ifndef __DA732X_H_ -#define __DA732X_H +#define __DA732X_H_ #include <sound/soc.h> diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 4a063fa88526..7e111865946a 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, - {"DMICL", NULL, "DMICL_ENA"}, - {"DMICR", NULL, "DMICR_ENA"}, {"DMICL", NULL, "AHPF"}, {"DMICR", NULL, "AHPF"}, @@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"DMIC Mux", "ADC", "ADCR"}, {"DMIC Mux", "DMIC", "DMICL"}, {"DMIC Mux", "DMIC", "DMICR"}, + {"DMIC Mux", "DMIC", "DMICL_ENA"}, + {"DMIC Mux", "DMIC", "DMICR_ENA"}, {"LBENL Mux", "Normal", "DMIC Mux"}, {"LBENL Mux", "Loopback", "LTENL Mux"}, @@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!max98090->master && dai->active == 1) + queue_delayed_work(system_power_efficient_wq, + &max98090->pll_det_enable_work, + msecs_to_jiffies(10)); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!max98090->master && dai->active == 1) + schedule_work(&max98090->pll_det_disable_work); + break; + default: + break; + } + + return 0; +} + +static void max98090_pll_det_enable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, + pll_det_enable_work.work); + struct snd_soc_codec *codec = max98090->codec; + unsigned int status, mask; + + /* + * Clear status register in order to clear possibly already occurred + * PLL unlock. If PLL hasn't still locked, the status will be set + * again and PLL unlock interrupt will occur. + * Note this will clear all status bits + */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + + /* + * Queue jack work in case jack state has just changed but handler + * hasn't run yet + */ + regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); + status &= mask; + if (status & M98090_JDET_MASK) + queue_delayed_work(system_power_efficient_wq, + &max98090->jack_work, + msecs_to_jiffies(100)); + + /* Enable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, + 1 << M98090_IULK_SHIFT); +} + +static void max98090_pll_det_disable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_det_disable_work); + struct snd_soc_codec *codec = max98090->codec; + + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + + /* Disable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, 0); +} + +static void max98090_pll_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_work); + struct snd_soc_codec *codec = max98090->codec; + + if (!snd_soc_codec_is_active(codec)) + return; + + dev_info(codec->dev, "PLL unlocked\n"); + + /* Toggle shutdown OFF then ON */ + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, 0); + msleep(10); + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, M98090_SHDNN_MASK); + + /* Give PLL time to lock */ + msleep(10); +} + static void max98090_jack_work(struct work_struct *work) { struct max98090_priv *max98090 = container_of(work, @@ -2103,8 +2199,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data) if (active & M98090_SLD_MASK) dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - if (active & M98090_ULK_MASK) - dev_err(codec->dev, "M98090_ULK_MASK\n"); + if (active & M98090_ULK_MASK) { + dev_dbg(codec->dev, "M98090_ULK_MASK\n"); + schedule_work(&max98090->pll_work); + } if (active & M98090_JDET_MASK) { dev_dbg(codec->dev, "M98090_JDET_MASK\n"); @@ -2177,6 +2275,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = { .set_tdm_slot = max98090_set_tdm_slot, .hw_params = max98090_dai_hw_params, .digital_mute = max98090_dai_digital_mute, + .trigger = max98090_dai_trigger, }; static struct snd_soc_dai_driver max98090_dai[] = { @@ -2258,6 +2357,11 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); + INIT_DELAYED_WORK(&max98090->pll_det_enable_work, + max98090_pll_det_enable_work); + INIT_WORK(&max98090->pll_det_disable_work, + max98090_pll_det_disable_work); + INIT_WORK(&max98090->pll_work, max98090_pll_work); /* Enable jack detection */ snd_soc_write(codec, M98090_REG_JACK_DETECT, @@ -2310,6 +2414,9 @@ static int max98090_remove(struct snd_soc_codec *codec) struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); cancel_delayed_work_sync(&max98090->jack_work); + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + cancel_work_sync(&max98090->pll_det_disable_work); + cancel_work_sync(&max98090->pll_work); return 0; } diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index cf1b6062ba8c..14427a566f41 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1532,6 +1532,9 @@ struct max98090_priv { int irq; int jack_state; struct delayed_work jack_work; + struct delayed_work pll_det_enable_work; + struct work_struct pll_det_disable_work; + struct work_struct pll_work; struct snd_soc_jack *jack; unsigned int dai_fmt; int tdm_slots; diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 163ec3855fd4..0c8aefab404c 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds = pcm512x_ramp_step_text); static const struct snd_kcontrol_new pcm512x_controls[] = { -SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, +SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), -SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, +SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, PCM512x_RQMR_SHIFT, 1, 1), SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e4f6102efc1a..b86b426f159d 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -51,7 +51,7 @@ static struct reg_default rt286_index_def[] = { { 0x04, 0xaf01 }, { 0x08, 0x000d }, { 0x09, 0xd810 }, - { 0x0a, 0x0060 }, + { 0x0a, 0x0120 }, { 0x0b, 0x0000 }, { 0x0d, 0x2800 }, { 0x0f, 0x0000 }, @@ -60,7 +60,7 @@ static struct reg_default rt286_index_def[] = { { 0x33, 0x0208 }, { 0x49, 0x0004 }, { 0x4f, 0x50e9 }, - { 0x50, 0x2c00 }, + { 0x50, 0x2000 }, { 0x63, 0x2902 }, { 0x67, 0x1111 }, { 0x68, 0x1016 }, @@ -104,7 +104,6 @@ static const struct reg_default rt286_reg[] = { { 0x02170700, 0x00000000 }, { 0x02270100, 0x00000000 }, { 0x02370100, 0x00000000 }, - { 0x02040000, 0x00004002 }, { 0x01870700, 0x00000020 }, { 0x00830000, 0x000000c3 }, { 0x00930000, 0x000000c3 }, @@ -192,7 +191,6 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) /*handle index registers*/ if (reg <= 0xff) { rt286_hw_write(client, RT286_COEF_INDEX, reg); - reg = RT286_PROC_COEF; for (i = 0; i < INDEX_CACHE_SIZE; i++) { if (reg == rt286->index_cache[i].reg) { rt286->index_cache[i].def = value; @@ -200,6 +198,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) } } + reg = RT286_PROC_COEF; } data[0] = (reg >> 24) & 0xff; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 6bc6efdec550..f1ec6e6bd08a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2059,6 +2059,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { static const struct regmap_config rt5640_regmap = { .reg_bits = 8, .val_bits = 16, + .use_single_rw = true, .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) * RT5640_PR_SPACING), diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 67f14556462f..5337c448b5e3 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -2135,10 +2135,10 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "BST2", NULL, "IN2P" }, { "BST2", NULL, "IN2N" }, - { "IN1P", NULL, "micbias1" }, - { "IN1N", NULL, "micbias1" }, - { "IN2P", NULL, "micbias1" }, - { "IN2N", NULL, "micbias1" }, + { "IN1P", NULL, "MICBIAS1" }, + { "IN1N", NULL, "MICBIAS1" }, + { "IN2P", NULL, "MICBIAS1" }, + { "IN2N", NULL, "MICBIAS1" }, { "ADC 1", NULL, "BST1" }, { "ADC 1", NULL, "ADC 1 power" }, diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 484b3bbe8624..4021cd435740 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -647,7 +647,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type, return -ENOMEM; dev_set_drvdata(dev, ssm2602); - ssm2602->type = SSM2602; + ssm2602->type = type; ssm2602->regmap = regmap; return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 9aa1323fb2ab..89c748dd3d6e 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -4,7 +4,7 @@ * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver * * Copyright (C) 2012 ST Microelectronics - * Rajeev Kumar <rajeev-dlh.kumar@st.com> + * Rajeev Kumar <rajeevkumar.linux@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -426,5 +426,5 @@ static struct i2c_driver sta529_i2c_driver = { module_i2c_driver(sta529_i2c_driver); MODULE_DESCRIPTION("ASoC STA529 codec driver"); -MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); +MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0f64c7890eed..aea9e1ff9126 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -189,46 +189,57 @@ static const struct aic31xx_rate_divs aic31xx_divs[] = { /* mclk rate pll: p j d dosr ndac mdac aors nadc madc */ /* 8k rate */ {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, {24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2}, {25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, {24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2}, {25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, {24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2}, {25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, {24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2}, {25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, {24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2}, {25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, {24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2}, {25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, {24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2}, {25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, {24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2}, {25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, {24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2}, {25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, {24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2}, {25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, {24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2}, {25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2}, }; @@ -680,7 +691,9 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, struct snd_pcm_hw_params *params) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); + int bclk_score = snd_soc_params_to_frame_size(params); int bclk_n = 0; + int match = -1; int i; /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ @@ -691,15 +704,37 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { if (aic31xx_divs[i].rate == params_rate(params) && - aic31xx_divs[i].mclk == aic31xx->sysclk) - break; + aic31xx_divs[i].mclk == aic31xx->sysclk) { + int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) % + snd_soc_params_to_frame_size(params); + int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) / + snd_soc_params_to_frame_size(params); + if (s < bclk_score && bn > 0) { + match = i; + bclk_n = bn; + bclk_score = s; + } + } } - if (i == ARRAY_SIZE(aic31xx_divs)) { - dev_err(codec->dev, "%s: Sampling rate %u not supported\n", + if (match == -1) { + dev_err(codec->dev, + "%s: Sample rate (%u) and format not supported\n", __func__, params_rate(params)); + /* See bellow for details how fix this. */ return -EINVAL; } + if (bclk_score != 0) { + dev_warn(codec->dev, "Can not produce exact bitclock"); + /* This is fine if using dsp format, but if using i2s + there may be trouble. To fix the issue edit the + aic31xx_divs table for your mclk and sample + rate. Details can be found from: + http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf + Section: 5.6 CLOCK Generation and PLL + */ + } + i = match; /* PLL configuration */ snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, @@ -729,14 +764,6 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr); /* Bit clock divider configuration. */ - bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) - / snd_soc_params_to_frame_size(params); - if (bclk_n == 0) { - dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n", - __func__); - return -EINVAL; - } - snd_soc_update_bits(codec, AIC31XX_BCLKN, AIC31XX_PLL_MASK, bclk_n); |