ASoC: tlv320aic31xx: configure output common-mode voltage
authorLucas Stach <l.stach@pengutronix.de>
Mon, 18 Nov 2019 15:12:06 +0000 (16:12 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 18 Nov 2019 16:11:47 +0000 (16:11 +0000)
The tlv320aic31xx devices allow to adjust the output common-mode voltage
for best analog performance. The datasheet states that the common mode
voltage should be set to be <= AVDD/2.

This changes allows to configure the output common-mode voltage via a DT
property. If the property is absent the voltage is automatically chosen
as the highest voltage below/equal to AVDD/2.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Link: https://lore.kernel.org/r/20191118151207.28576-1-l.stach@pengutronix.de
Signed-off-by: Mark Brown <broonie@kernel.org>
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic31xx.h

index 5b3c33bb99e57a4d21384aa7c1d36b062f14ab12..e372303697dc0a08970135b562963fa47fb1f3a2 100644 (file)
@@ -29,6 +29,11 @@ Optional properties:
         3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
        If this node is not mentioned or if the value is unknown, then
        micbias is set to 2.0V.
+- ai31xx-ocmv - output common-mode voltage setting
+        0 - 1.35V,
+        1 - 1.5V,
+        2 - 1.65V,
+        3 - 1.8V
 
 Deprecated properties:
 
index df627a08def95d459f775d7983780a22f3cd820f..f6f19fdc72f56ac2b48c9b9a5dcc5fd005468f5f 100644 (file)
@@ -171,6 +171,7 @@ struct aic31xx_priv {
        int rate_div_line;
        bool master_dapm_route_applied;
        int irq;
+       u8 ocmv; /* output common-mode voltage */
 };
 
 struct aic31xx_rate_divs {
@@ -1312,6 +1313,11 @@ static int aic31xx_codec_probe(struct snd_soc_component *component)
        if (ret)
                return ret;
 
+       /* set output common-mode voltage */
+       snd_soc_component_update_bits(component, AIC31XX_HPDRIVER,
+                                     AIC31XX_HPD_OCMV_MASK,
+                                     aic31xx->ocmv << AIC31XX_HPD_OCMV_SHIFT);
+
        return 0;
 }
 
@@ -1501,6 +1507,43 @@ exit:
                return IRQ_NONE;
 }
 
+static void aic31xx_configure_ocmv(struct aic31xx_priv *priv)
+{
+       struct device *dev = priv->dev;
+       int dvdd, avdd;
+       u32 value;
+
+       if (dev->fwnode &&
+           fwnode_property_read_u32(dev->fwnode, "ai31xx-ocmv", &value)) {
+               /* OCMV setting is forced by DT */
+               if (value <= 3) {
+                       priv->ocmv = value;
+                       return;
+               }
+       }
+
+       avdd = regulator_get_voltage(priv->supplies[3].consumer);
+       dvdd = regulator_get_voltage(priv->supplies[5].consumer);
+
+       if (avdd > 3600000 || dvdd > 1950000) {
+               dev_warn(dev,
+                        "Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
+                        avdd, dvdd);
+       } else if (avdd == 3600000 && dvdd == 1950000) {
+               priv->ocmv = AIC31XX_HPD_OCMV_1_8V;
+       } else if (avdd >= 3300000 && dvdd >= 1800000) {
+               priv->ocmv = AIC31XX_HPD_OCMV_1_65V;
+       } else if (avdd >= 3000000 && dvdd >= 1650000) {
+               priv->ocmv = AIC31XX_HPD_OCMV_1_5V;
+       } else if (avdd >= 2700000 && dvdd >= 1525000) {
+               priv->ocmv = AIC31XX_HPD_OCMV_1_35V;
+       } else {
+               dev_warn(dev,
+                        "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
+                        avdd, dvdd);
+       }
+}
+
 static int aic31xx_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
@@ -1570,6 +1613,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       aic31xx_configure_ocmv(aic31xx);
+
        if (aic31xx->irq > 0) {
                regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1,
                                   AIC31XX_GPIO1_FUNC_MASK,
index cb024955c978400d6b6cdae3b9fc7f5bf21a0679..83a8c7604cc3a5326f8922c016c005e35af56afc 100644 (file)
@@ -232,6 +232,14 @@ struct aic31xx_pdata {
 #define AIC31XX_HSD_HP                 0x01
 #define AIC31XX_HSD_HS                 0x03
 
+/* AIC31XX_HPDRIVER */
+#define AIC31XX_HPD_OCMV_MASK          GENMASK(4, 3)
+#define AIC31XX_HPD_OCMV_SHIFT         3
+#define AIC31XX_HPD_OCMV_1_35V         0x0
+#define AIC31XX_HPD_OCMV_1_5V          0x1
+#define AIC31XX_HPD_OCMV_1_65V         0x2
+#define AIC31XX_HPD_OCMV_1_8V          0x3
+
 /* AIC31XX_MICBIAS */
 #define AIC31XX_MICBIAS_MASK           GENMASK(1, 0)
 #define AIC31XX_MICBIAS_SHIFT          0