ASoC: tlv320aic3x: Support for OCMV configuration
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Thu, 31 Aug 2017 08:49:47 +0000 (11:49 +0300)
committerMark Brown <broonie@kernel.org>
Thu, 31 Aug 2017 09:24:01 +0000 (10:24 +0100)
´╗┐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>
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h

index 47a213c411ce922321e692ecca849390cbcd53e8..ba5b45c483f5da6c3b1ced1d3d43416fc0f1851e 100644 (file)
@@ -26,6 +26,11 @@ Optional properties:
        3 - MICBIAS output is connected to AVDD,
        If this node is not mentioned or if the value is incorrect, then MicBias
        is powered down.
+- ai3x-ocmv - Output Common-Mode Voltage selection:
+       0 - 1.35V,
+       1 - 1.5V,
+       2 - 1.65V,
+       3 - 1.8V
 - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the
   device as covered in Documentation/devicetree/bindings/regulator/regulator.txt
 
index 29bf8c81ae028c0dad3dbff8c4cde406bf693c07..ca880859f0c32a1ff9576dd4cfc16174bd11bbef 100644 (file)
@@ -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));
index 89fa692df206d3c5f1bbf9c3c1eca7700f5a7a6a..34c35196aa0dfcc663b239103ac733b5e0551d23 100644 (file)
 #define MICBIAS_LEVEL_SHIFT    (6)
 #define MICBIAS_LEVEL_MASK     (3 << 6)
 
+/* HPOUT_SC */
+#define HPOUT_SC_OCMV_MASK     (3 << 6)
+#define HPOUT_SC_OCMV_SHIFT    (6)
+#define HPOUT_SC_OCMV_1_35V    0
+#define HPOUT_SC_OCMV_1_5V     1
+#define HPOUT_SC_OCMV_1_65V    2
+#define HPOUT_SC_OCMV_1_8V     3
+
 /* headset detection / button API */
 
 /* The AIC3x supports detection of stereo headsets (GND + left + right signal)