summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/tlv320aic3x.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2017-08-31 11:49:47 +0300
committerMark Brown <broonie@kernel.org>2017-08-31 12:24:01 +0300
commit19b0fa11bb1c0c24296c9f670a37c091bd3c815d (patch)
treec2168c918eb3192ab2c53a49d2885bb30023c325 /sound/soc/codecs/tlv320aic3x.c
parent5771a8c08880cdca3bfb4a3fc6d309d6bba20877 (diff)
downloadlinux-19b0fa11bb1c0c24296c9f670a37c091bd3c815d.tar.xz
ASoC: tlv320aic3x: Support for OCMV configuration
In aic3x class of devices Output Common-Mode Voltage can be configured for better analog performance. The OCMV value depends on the Analog and digital domain power supply voltage configuration. The default OCMV of 1.35V gives best performance when AVDD is around 2.7V and DVDD is 1.525V, but for higher AVDD/DVDD higher OCMV setting is recommended. The patch gives an automatic way of guessing the best OCMV which can be overwritten by a DT parameter if needed. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 29bf8c81ae02..ca880859f0c3 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -93,6 +93,8 @@ struct aic3x_priv {
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
+ /* Output Common-Mode Voltage */
+ u8 ocmv;
};
static const struct reg_default aic3x_reg[] = {
@@ -1572,6 +1574,10 @@ static int aic3x_init(struct snd_soc_codec *codec)
break;
}
+ /* Output common-mode voltage = 1.5 V */
+ snd_soc_update_bits(codec, HPOUT_SC, HPOUT_SC_OCMV_MASK,
+ aic3x->ocmv << HPOUT_SC_OCMV_SHIFT);
+
return 0;
}
@@ -1699,6 +1705,43 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
},
};
+static void aic3x_configure_ocmv(struct i2c_client *client)
+{
+ struct device_node *np = client->dev.of_node;
+ struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+ u32 value;
+ int dvdd, avdd;
+
+ if (np && !of_property_read_u32(np, "ai3x-ocmv", &value)) {
+ /* OCMV setting is forced by DT */
+ if (value <= 3) {
+ aic3x->ocmv = value;
+ return;
+ }
+ }
+
+ dvdd = regulator_get_voltage(aic3x->supplies[1].consumer);
+ avdd = regulator_get_voltage(aic3x->supplies[2].consumer);
+
+ if (avdd > 3600000 || dvdd > 1950000) {
+ dev_warn(&client->dev,
+ "Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
+ avdd, dvdd);
+ } else if (avdd == 3600000 && dvdd == 1950000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_8V;
+ } else if (avdd > 3300000 && dvdd > 1800000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_65V;
+ } else if (avdd > 3000000 && dvdd > 1650000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_5V;
+ } else if (avdd >= 2700000 && dvdd >= 1525000) {
+ aic3x->ocmv = HPOUT_SC_OCMV_1_35V;
+ } else {
+ dev_warn(&client->dev,
+ "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
+ avdd, dvdd);
+ }
+}
+
/*
* AIC3X 2 wire address can be up to 4 devices with device addresses
* 0x18, 0x19, 0x1A, 0x1B
@@ -1816,6 +1859,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
goto err_gpio;
}
+ aic3x_configure_ocmv(i2c);
+
if (aic3x->model == AIC3X_MODEL_3007) {
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
ARRAY_SIZE(aic3007_class_d));