diff options
Diffstat (limited to 'sound/soc/codecs/ad193x.c')
-rw-r--r-- | sound/soc/codecs/ad193x.c | 209 |
1 files changed, 98 insertions, 111 deletions
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 1206021..a4a6bef 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -30,21 +30,23 @@ struct ad193x_priv { /* * AD193X volume/mute/de-emphasis etc. controls */ -static const char *ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; +static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; static const struct soc_enum ad193x_deemp_enum = SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); +static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); + static const struct snd_kcontrol_new ad193x_snd_controls[] = { /* DAC volume control */ - SOC_DOUBLE_R("DAC1 Volume", AD193X_DAC_L1_VOL, - AD193X_DAC_R1_VOL, 0, 0xFF, 1), - SOC_DOUBLE_R("DAC2 Volume", AD193X_DAC_L2_VOL, - AD193X_DAC_R2_VOL, 0, 0xFF, 1), - SOC_DOUBLE_R("DAC3 Volume", AD193X_DAC_L3_VOL, - AD193X_DAC_R3_VOL, 0, 0xFF, 1), - SOC_DOUBLE_R("DAC4 Volume", AD193X_DAC_L4_VOL, - AD193X_DAC_R4_VOL, 0, 0xFF, 1), + SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL, + AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv), + SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL, + AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv), + SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL, + AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv), + SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL, + AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv), /* ADC switch control */ SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE, @@ -75,6 +77,7 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("DAC1OUT"), SND_SOC_DAPM_OUTPUT("DAC2OUT"), SND_SOC_DAPM_OUTPUT("DAC3OUT"), @@ -84,16 +87,17 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { }; static const struct snd_soc_dapm_route audio_paths[] = { - { "DAC", NULL, "PLL_PWR" }, - { "ADC", NULL, "PLL_PWR" }, + { "DAC", NULL, "SYSCLK" }, + { "ADC", NULL, "SYSCLK" }, { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, - { "DAC1OUT", "DAC1 Switch", "DAC" }, - { "DAC2OUT", "DAC2 Switch", "DAC" }, - { "DAC3OUT", "DAC3 Switch", "DAC" }, - { "DAC4OUT", "DAC4 Switch", "DAC" }, - { "ADC", "ADC1 Switch", "ADC1IN" }, - { "ADC", "ADC2 Switch", "ADC2IN" }, + { "DAC1OUT", NULL, "DAC" }, + { "DAC2OUT", NULL, "DAC" }, + { "DAC3OUT", NULL, "DAC" }, + { "DAC4OUT", NULL, "DAC" }, + { "ADC", NULL, "ADC1IN" }, + { "ADC", NULL, "ADC2IN" }, + { "SYSCLK", NULL, "PLL_PWR" }, }; /* @@ -102,14 +106,14 @@ static const struct snd_soc_dapm_route audio_paths[] = { static int ad193x_mute(struct snd_soc_dai *dai, int mute) { - struct snd_soc_codec *codec = dai->codec; + struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec); if (mute) - snd_soc_update_bits(codec, AD193X_DAC_CTRL2, + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, AD193X_DAC_MASTER_MUTE, AD193X_DAC_MASTER_MUTE); else - snd_soc_update_bits(codec, AD193X_DAC_CTRL2, + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, AD193X_DAC_MASTER_MUTE, 0); return 0; @@ -118,36 +122,30 @@ static int ad193x_mute(struct snd_soc_dai *dai, int mute) static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int width) { - struct snd_soc_codec *codec = dai->codec; - int dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1); - int adc_reg = snd_soc_read(codec, AD193X_ADC_CTRL2); - - dac_reg &= ~AD193X_DAC_CHAN_MASK; - adc_reg &= ~AD193X_ADC_CHAN_MASK; + struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec); + unsigned int channels; switch (slots) { case 2: - dac_reg |= AD193X_DAC_2_CHANNELS << AD193X_DAC_CHAN_SHFT; - adc_reg |= AD193X_ADC_2_CHANNELS << AD193X_ADC_CHAN_SHFT; + channels = AD193X_2_CHANNELS; break; case 4: - dac_reg |= AD193X_DAC_4_CHANNELS << AD193X_DAC_CHAN_SHFT; - adc_reg |= AD193X_ADC_4_CHANNELS << AD193X_ADC_CHAN_SHFT; + channels = AD193X_4_CHANNELS; break; case 8: - dac_reg |= AD193X_DAC_8_CHANNELS << AD193X_DAC_CHAN_SHFT; - adc_reg |= AD193X_ADC_8_CHANNELS << AD193X_ADC_CHAN_SHFT; + channels = AD193X_8_CHANNELS; break; case 16: - dac_reg |= AD193X_DAC_16_CHANNELS << AD193X_DAC_CHAN_SHFT; - adc_reg |= AD193X_ADC_16_CHANNELS << AD193X_ADC_CHAN_SHFT; + channels = AD193X_16_CHANNELS; break; default: return -EINVAL; } - snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg); - snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg); + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, + AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT); + regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, + AD193X_ADC_CHAN_MASK, channels << AD193X_ADC_CHAN_SHFT); return 0; } @@ -155,24 +153,20 @@ static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; - int adc_reg1, adc_reg2, dac_reg; - - adc_reg1 = snd_soc_read(codec, AD193X_ADC_CTRL1); - adc_reg2 = snd_soc_read(codec, AD193X_ADC_CTRL2); - dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1); + struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec_dai->codec); + unsigned int adc_serfmt = 0; + unsigned int adc_fmt = 0; + unsigned int dac_fmt = 0; /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - adc_reg1 &= ~AD193X_ADC_SERFMT_MASK; - adc_reg1 |= AD193X_ADC_SERFMT_TDM; + adc_serfmt |= AD193X_ADC_SERFMT_TDM; break; case SND_SOC_DAIFMT_DSP_A: - adc_reg1 &= ~AD193X_ADC_SERFMT_MASK; - adc_reg1 |= AD193X_ADC_SERFMT_AUX; + adc_serfmt |= AD193X_ADC_SERFMT_AUX; break; default: return -EINVAL; @@ -180,29 +174,20 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ - adc_reg2 &= ~AD193X_ADC_LEFT_HIGH; - adc_reg2 &= ~AD193X_ADC_BCLK_INV; - dac_reg &= ~AD193X_DAC_LEFT_HIGH; - dac_reg &= ~AD193X_DAC_BCLK_INV; break; case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */ - adc_reg2 |= AD193X_ADC_LEFT_HIGH; - adc_reg2 &= ~AD193X_ADC_BCLK_INV; - dac_reg |= AD193X_DAC_LEFT_HIGH; - dac_reg &= ~AD193X_DAC_BCLK_INV; + adc_fmt |= AD193X_ADC_LEFT_HIGH; + dac_fmt |= AD193X_DAC_LEFT_HIGH; break; case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */ - adc_reg2 &= ~AD193X_ADC_LEFT_HIGH; - adc_reg2 |= AD193X_ADC_BCLK_INV; - dac_reg &= ~AD193X_DAC_LEFT_HIGH; - dac_reg |= AD193X_DAC_BCLK_INV; + adc_fmt |= AD193X_ADC_BCLK_INV; + dac_fmt |= AD193X_DAC_BCLK_INV; break; - case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */ - adc_reg2 |= AD193X_ADC_LEFT_HIGH; - adc_reg2 |= AD193X_ADC_BCLK_INV; - dac_reg |= AD193X_DAC_LEFT_HIGH; - dac_reg |= AD193X_DAC_BCLK_INV; + adc_fmt |= AD193X_ADC_LEFT_HIGH; + adc_fmt |= AD193X_ADC_BCLK_INV; + dac_fmt |= AD193X_DAC_LEFT_HIGH; + dac_fmt |= AD193X_DAC_BCLK_INV; break; default: return -EINVAL; @@ -210,36 +195,31 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ - adc_reg2 |= AD193X_ADC_LCR_MASTER; - adc_reg2 |= AD193X_ADC_BCLK_MASTER; - dac_reg |= AD193X_DAC_LCR_MASTER; - dac_reg |= AD193X_DAC_BCLK_MASTER; + adc_fmt |= AD193X_ADC_LCR_MASTER; + adc_fmt |= AD193X_ADC_BCLK_MASTER; + dac_fmt |= AD193X_DAC_LCR_MASTER; + dac_fmt |= AD193X_DAC_BCLK_MASTER; break; case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ - adc_reg2 |= AD193X_ADC_LCR_MASTER; - adc_reg2 &= ~AD193X_ADC_BCLK_MASTER; - dac_reg |= AD193X_DAC_LCR_MASTER; - dac_reg &= ~AD193X_DAC_BCLK_MASTER; + adc_fmt |= AD193X_ADC_LCR_MASTER; + dac_fmt |= AD193X_DAC_LCR_MASTER; break; case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ - adc_reg2 &= ~AD193X_ADC_LCR_MASTER; - adc_reg2 |= AD193X_ADC_BCLK_MASTER; - dac_reg &= ~AD193X_DAC_LCR_MASTER; - dac_reg |= AD193X_DAC_BCLK_MASTER; + adc_fmt |= AD193X_ADC_BCLK_MASTER; + dac_fmt |= AD193X_DAC_BCLK_MASTER; break; case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ - adc_reg2 &= ~AD193X_ADC_LCR_MASTER; - adc_reg2 &= ~AD193X_ADC_BCLK_MASTER; - dac_reg &= ~AD193X_DAC_LCR_MASTER; - dac_reg &= ~AD193X_DAC_BCLK_MASTER; break; default: return -EINVAL; } - snd_soc_write(codec, AD193X_ADC_CTRL1, adc_reg1); - snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg2); - snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg); + regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, + AD193X_ADC_SERFMT_MASK, adc_serfmt); + regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, + AD193X_ADC_FMT_MASK, adc_fmt); + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, + AD193X_DAC_FMT_MASK, dac_fmt); return 0; } @@ -299,20 +279,20 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, break; } - snd_soc_update_bits(codec, AD193X_PLL_CLK_CTRL0, + regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0, AD193X_PLL_INPUT_MASK, master_rate); - snd_soc_update_bits(codec, AD193X_DAC_CTRL2, + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, AD193X_DAC_WORD_LEN_MASK, word_len << AD193X_DAC_WORD_LEN_SHFT); - snd_soc_update_bits(codec, AD193X_ADC_CTRL1, + regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, AD193X_ADC_WORD_LEN_MASK, word_len); return 0; } -static struct snd_soc_dai_ops ad193x_dai_ops = { +static const struct snd_soc_dai_ops ad193x_dai_ops = { .hw_params = ad193x_hw_params, .digital_mute = ad193x_mute, .set_tdm_slot = ad193x_set_tdm_slot, @@ -345,7 +325,6 @@ static struct snd_soc_dai_driver ad193x_dai = { static int ad193x_probe(struct snd_soc_codec *codec) { struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; codec->control_data = ad193x->regmap; @@ -358,32 +337,37 @@ static int ad193x_probe(struct snd_soc_codec *codec) /* default setting for ad193x */ /* unmute dac channels */ - snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0); + regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); /* de-emphasis: 48kHz, powedown dac */ - snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A); + regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); /* powerdown dac, dac in tdm mode */ - snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41); + regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41); /* high-pass filter enable */ - snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3); + regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); /* sata delay=1, adc aux mode */ - snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43); + regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43); /* pll input: mclki/xi */ - snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ - snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); - - snd_soc_add_controls(codec, ad193x_snd_controls, - ARRAY_SIZE(ad193x_snd_controls)); - snd_soc_dapm_new_controls(dapm, ad193x_dapm_widgets, - ARRAY_SIZE(ad193x_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); + regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ + regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04); return ret; } static struct snd_soc_codec_driver soc_codec_dev_ad193x = { .probe = ad193x_probe, + .controls = ad193x_snd_controls, + .num_controls = ARRAY_SIZE(ad193x_snd_controls), + .dapm_widgets = ad193x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), }; +static bool adau193x_reg_volatile(struct device *dev, unsigned int reg) +{ + return false; +} + #if defined(CONFIG_SPI_MASTER) static const struct regmap_config ad193x_spi_regmap_config = { @@ -391,6 +375,9 @@ static const struct regmap_config ad193x_spi_regmap_config = { .reg_bits = 16, .read_flag_mask = 0x09, .write_flag_mask = 0x08, + + .max_register = AD193X_NUM_REGS - 1, + .volatile_reg = adau193x_reg_volatile, }; static int __devinit ad193x_spi_probe(struct spi_device *spi) @@ -398,14 +385,15 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi) struct ad193x_priv *ad193x; int ret; - ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); + ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), + GFP_KERNEL); if (ad193x == NULL) return -ENOMEM; ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config); if (IS_ERR(ad193x->regmap)) { ret = PTR_ERR(ad193x->regmap); - goto err_free; + goto err_out; } spi_set_drvdata(spi, ad193x); @@ -419,9 +407,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi) err_regmap_exit: regmap_exit(ad193x->regmap); -err_free: - kfree(ad193x); - +err_out: return ret; } @@ -431,7 +417,6 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi) snd_soc_unregister_codec(&spi->dev); regmap_exit(ad193x->regmap); - kfree(ad193x); return 0; } @@ -450,6 +435,9 @@ static struct spi_driver ad193x_spi_driver = { static const struct regmap_config ad193x_i2c_regmap_config = { .val_bits = 8, .reg_bits = 8, + + .max_register = AD193X_NUM_REGS - 1, + .volatile_reg = adau193x_reg_volatile, }; static const struct i2c_device_id ad193x_id[] = { @@ -465,14 +453,15 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client, struct ad193x_priv *ad193x; int ret; - ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); + ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), + GFP_KERNEL); if (ad193x == NULL) return -ENOMEM; ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config); if (IS_ERR(ad193x->regmap)) { ret = PTR_ERR(ad193x->regmap); - goto err_free; + goto err_out; } i2c_set_clientdata(client, ad193x); @@ -486,8 +475,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client, err_regmap_exit: regmap_exit(ad193x->regmap); -err_free: - kfree(ad193x); +err_out: return ret; } @@ -497,7 +485,6 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); regmap_exit(ad193x->regmap); - kfree(ad193x); return 0; } |