ASoC: tlv320aic31xx: configure output common-mode voltage

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>
This commit is contained in:
Lucas Stach 2019-11-18 16:12:06 +01:00 committed by Mark Brown
parent 653c28afa7
commit e48fdb53bd
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 58 additions and 0 deletions

View 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:

View 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 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
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,

View 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