diff options
| author | Deven Patel <cdevenp@codeaurora.org> | 2015-10-28 15:26:31 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:11:51 -0700 |
| commit | 9f1c58fa3a32a2fdd609b21b7c7f42ef3f3fa661 (patch) | |
| tree | 654f5fe0aa6acc622d9bc37699212f1f85f2e398 | |
| parent | 33b83ae59add4df08febcff1dabb84d853b0d818 (diff) | |
ASoC: wcd9335: Add I2S/I2C interface support for codec
WCD9335 can transport data to and from device through I2S and I2C.
Update the change to support I2S/I2C interface.
Change-Id: Ifdec293510adf685410a4fb6ef6a3e939c4ee04b
Signed-off-by: Deven Patel <cdevenp@codeaurora.org>
| -rwxr-xr-x | sound/soc/codecs/wcd9335.c | 268 |
1 files changed, 248 insertions, 20 deletions
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index acd0d5d71605..a2a0105a28e7 100755 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -454,7 +454,7 @@ static const struct wcd9xxx_ch tasha_tx_chs[TASHA_TX_MAX] = { WCD9XXX_CH(15, 15), }; -static const u32 vport_check_table[NUM_CODEC_DAIS] = { +static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = { 0, /* AIF1_PB */ BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_MAD_TX), /* AIF1_CAP */ 0, /* AIF2_PB */ @@ -465,6 +465,12 @@ static const u32 vport_check_table[NUM_CODEC_DAIS] = { BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP), /* AIF4_MAD_TX */ }; +static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = { + 0, /* AIF1_PB */ + BIT(AIF2_CAP), /* AIF1_CAP */ + 0, /* AIF2_PB */ + BIT(AIF1_CAP), /* AIF2_CAP */ +}; /* Codec supports 2 IIR filters */ enum { @@ -2165,13 +2171,6 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol, mutex_lock(&tasha_p->codec_mutex); - if (dai_id >= ARRAY_SIZE(vport_check_table)) { - dev_err(codec->dev, "%s: dai_id: %d, out of bounds\n", - __func__, dai_id); - mutex_unlock(&tasha_p->codec_mutex); - return -EINVAL; - } - vtable = vport_check_table[dai_id]; if (tasha_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) { if (dai_id != AIF1_CAP) { dev_err(codec->dev, "%s: invalid AIF for I2C mode\n", @@ -2179,6 +2178,14 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol, mutex_unlock(&tasha_p->codec_mutex); return -EINVAL; } + vtable = vport_slim_check_table[dai_id]; + } else { + if (dai_id >= ARRAY_SIZE(vport_i2s_check_table)) { + dev_err(codec->dev, "%s: dai_id: %d, out of bounds\n", + __func__, dai_id); + return -EINVAL; + } + vtable = vport_i2s_check_table[dai_id]; } switch (dai_id) { case AIF1_CAP: @@ -3995,6 +4002,13 @@ static int tasha_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, return 0; } +static const struct snd_soc_dapm_widget tasha_dapm_i2s_widgets[] = { + SND_SOC_DAPM_SUPPLY("RX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0, 0, NULL, 0), +}; + static int tasha_codec_ear_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -5351,6 +5365,18 @@ static const struct soc_enum cf_int7_1_enum = static const struct soc_enum cf_int8_1_enum = SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text); +static const struct snd_soc_dapm_route audio_i2s_map[] = { + {"SLIM RX0 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX1 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX2 MUX", NULL, "RX_I2S_CTL"}, + {"SLIM RX3 MUX", NULL, "RX_I2S_CTL"}, + + {"SLIM TX6 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX7 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX8 MUX", NULL, "TX_I2S_CTL"}, + {"SLIM TX11 MUX", NULL, "TX_I2S_CTL"}, +}; + static const struct snd_soc_dapm_route audio_map[] = { /* MAD */ @@ -10186,6 +10212,9 @@ static int tasha_hw_params(struct snd_pcm_substream *substream, struct tasha_priv *tasha = snd_soc_codec_get_drvdata(dai->codec); int ret; int tx_fs_rate = -EINVAL; + int rx_fs_rate = -EINVAL; + int i2s_bit_mode; + struct snd_soc_codec *codec = dai->codec; pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__, dai->name, dai->id, params_rate(params), @@ -10202,12 +10231,47 @@ static int tasha_hw_params(struct snd_pcm_substream *substream, switch (params_width(params)) { case 16: tasha->dai[dai->id].bit_width = 16; + i2s_bit_mode = 0x01; break; case 24: tasha->dai[dai->id].bit_width = 24; + i2s_bit_mode = 0x00; break; } tasha->dai[dai->id].rate = params_rate(params); + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + switch (params_rate(params)) { + case 8000: + rx_fs_rate = 0; + break; + case 16000: + rx_fs_rate = 1; + break; + case 32000: + rx_fs_rate = 2; + break; + case 48000: + rx_fs_rate = 3; + break; + case 96000: + rx_fs_rate = 4; + break; + case 192000: + rx_fs_rate = 5; + break; + default: + dev_err(tasha->dev, + "%s: Invalid RX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + }; + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x20, i2s_bit_mode << 5); + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x1c, (rx_fs_rate << 2)); + } break; case SNDRV_PCM_STREAM_CAPTURE: switch (params_rate(params)) { @@ -10232,12 +10296,12 @@ static int tasha_hw_params(struct snd_pcm_substream *substream, case 384000: tx_fs_rate = 7; break; - }; - if (tx_fs_rate < 0) { + default: dev_err(tasha->dev, "%s: Invalid TX sample rate: %d\n", - __func__, tx_fs_rate); + __func__, params_rate(params)); return -EINVAL; - } + + }; if (dai->id != AIF4_VIFEED && dai->id != AIF4_MAD_TX) { ret = tasha_set_decimator_rate(dai, tx_fs_rate, @@ -10252,18 +10316,46 @@ static int tasha_hw_params(struct snd_pcm_substream *substream, switch (params_width(params)) { case 16: tasha->dai[dai->id].bit_width = 16; + i2s_bit_mode = 0x01; break; case 24: tasha->dai[dai->id].bit_width = 24; + i2s_bit_mode = 0x00; break; case 32: tasha->dai[dai->id].bit_width = 32; + i2s_bit_mode = 0x00; break; default: dev_err(tasha->dev, "%s: Invalid format 0x%x\n", __func__, params_width(params)); return -EINVAL; }; + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x20, i2s_bit_mode << 5); + if (tx_fs_rate > 1) + tx_fs_rate--; + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x1c, tx_fs_rate << 2); + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, + 0x05, 0x05); + + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, + 0x05, 0x05); + + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, + 0x05, 0x05); + + snd_soc_update_bits(codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, + 0x05, 0x05); + } break; default: pr_err("%s: Invalid stream type %d\n", __func__, @@ -10278,6 +10370,38 @@ static int tasha_hw_params(struct snd_pcm_substream *substream, static int tasha_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(dai->codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* CPU is master */ + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + if (dai->id == AIF1_CAP) + snd_soc_update_bits(dai->codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x2, 0); + else if (dai->id == AIF1_PB) + snd_soc_update_bits(dai->codec, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x2, 0); + } + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* CPU is slave */ + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + if (dai->id == AIF1_CAP) + snd_soc_update_bits(dai->codec, + WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL, + 0x2, 0x2); + else if (dai->id == AIF1_PB) + snd_soc_update_bits(dai->codec, + WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL, + 0x2, 0x2); + } + break; + default: + return -EINVAL; + } return 0; } @@ -10428,6 +10552,65 @@ static struct snd_soc_dai_driver tasha_dai[] = { }, }; +static struct snd_soc_dai_driver tasha_i2s_dai[] = { + { + .name = "tasha_i2s_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tasha_dai_ops, + }, + { + .name = "tasha_i2s_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = TASHA_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tasha_dai_ops, + }, +}; + static void tasha_codec_power_gate_digital_core(struct tasha_priv *tasha) { struct snd_soc_codec *codec = tasha->codec; @@ -10829,6 +11012,21 @@ static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = { {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x04, 0x04}, }; +static const struct tasha_reg_mask_val tasha_codec_reg_i2c_defaults[] = { + {WCD9335_ANA_CLK_TOP, 0x20, 0x20}, + {WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x01}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x00}, + {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x01, 0x01}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, 0x05, 0x05}, + {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, 0x05, 0x05}, +}; + static const struct tasha_reg_mask_val tasha_codec_reg_init_common_val[] = { /* Rbuckfly/R_EAR(32) */ {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, @@ -11000,6 +11198,15 @@ static void tasha_update_reg_defaults(struct tasha_priv *tasha) tasha_codec_reg_defaults[i].reg, tasha_codec_reg_defaults[i].mask, tasha_codec_reg_defaults[i].val); + + tasha->intf_type = wcd9xxx_get_intf_type(); + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) + for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_i2c_defaults); i++) + wcd9xxx_reg_update_bits(&wcd9xxx->core_res, + tasha_codec_reg_i2c_defaults[i].reg, + tasha_codec_reg_i2c_defaults[i].mask, + tasha_codec_reg_i2c_defaults[i].val); + return; } @@ -11824,6 +12031,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) tasha->comp_enabled[i] = 0; tasha->spkr_gain_offset = RX_GAIN_OFFSET_0_DB; + tasha->intf_type = wcd9xxx_get_intf_type(); tasha_update_reg_reset_values(codec); pr_debug("%s: MCLK Rate = %x\n", __func__, control->mclk_rate); if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ) @@ -11885,7 +12093,16 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) goto err_hwdep; } - if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { + snd_soc_dapm_new_controls(dapm, tasha_dapm_i2s_widgets, + ARRAY_SIZE(tasha_dapm_i2s_widgets)); + snd_soc_dapm_add_routes(dapm, audio_i2s_map, + ARRAY_SIZE(audio_i2s_map)); + for (i = 0; i < ARRAY_SIZE(tasha_i2s_dai); i++) { + INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list); + init_waitqueue_head(&tasha->dai[i].dai_wait); + } + } else if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { for (i = 0; i < NUM_CODEC_DAIS; i++) { INIT_LIST_HEAD(&tasha->dai[i].wcd9xxx_ch_list); init_waitqueue_head(&tasha->dai[i].dai_wait); @@ -12317,6 +12534,13 @@ static int tasha_probe(struct platform_device *pdev) struct wcd9xxx_resmgr_v2 *resmgr; struct wcd9xxx_power_region *cdc_pwr; + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) { + if (apr_get_modem_state() == APR_SUBSYS_DOWN) { + dev_err(&pdev->dev, "%s: modem down\n", __func__); + return -EPROBE_DEFER; + } + } + tasha = devm_kzalloc(&pdev->dev, sizeof(struct tasha_priv), GFP_KERNEL); if (!tasha) { @@ -12351,14 +12575,17 @@ static int tasha_probe(struct platform_device *pdev) WCD_REGION_POWER_COLLAPSE_REMOVE, WCD9XXX_DIG_CORE_REGION_1); - if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) { + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, tasha_dai, ARRAY_SIZE(tasha_dai)); - if (ret) { - dev_err(&pdev->dev, "%s: Codec registration failed\n", - __func__); - goto cdc_reg_fail; - } + else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, + tasha_i2s_dai, + ARRAY_SIZE(tasha_i2s_dai)); + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed\n", + __func__); + goto cdc_reg_fail; } mutex_init(&tasha->codec_mutex); /* @@ -12407,7 +12634,8 @@ static int tasha_probe(struct platform_device *pdev) resmgr_remove: wcd_resmgr_remove(tasha->resmgr); unregister_codec: - if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + if ((wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) || + (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)) snd_soc_unregister_codec(&pdev->dev); cdc_reg_fail: devm_kfree(&pdev->dev, cdc_pwr); |
