ASoC: tlv320aic31xx: Add headphone/headset detection

This device can detect the insertion/removal of headphones and headsets.
Enable reporting this status by enabling this interrupt and forwarding
this to upper-layers if a jack has been defined.

This jack definition and the resulting operation from a jack detection
event must currently be defined by sound card platform code until CODEC
outputs to jack mappings can be defined generically.

Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Andrew F. Davis 2019-04-01 10:13:28 -05:00 committed by Mark Brown
parent 35146467bd
commit ebf3326cd9
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 58 additions and 1 deletions

View File

@ -25,6 +25,7 @@
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg)
case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
case AIC31XX_INTRDACFLAG2:
case AIC31XX_INTRADCFLAG2:
case AIC31XX_HSDETECT:
return true;
}
return false;
@ -163,6 +165,7 @@ struct aic31xx_priv {
struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
struct snd_soc_jack *jack;
unsigned int sysclk;
u8 p_div;
int rate_div_line;
@ -1261,6 +1264,20 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component,
return 0;
}
int aic31xx_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
aic31xx->jack = jack;
/* Enable/Disable jack detection */
regmap_write(aic31xx->regmap, AIC31XX_HSDETECT,
jack ? AIC31XX_HSD_ENABLE : 0);
return 0;
}
static int aic31xx_codec_probe(struct snd_soc_component *component)
{
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
@ -1301,6 +1318,7 @@ static int aic31xx_codec_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe,
.set_jack = aic31xx_set_jack,
.set_bias_level = aic31xx_set_bias_level,
.controls = common31xx_snd_controls,
.num_controls = ARRAY_SIZE(common31xx_snd_controls),
@ -1405,8 +1423,35 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
dev_err(dev, "Short circuit on Left output is detected\n");
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
if (value & AIC31XX_HSPLUG) {
unsigned int val;
int status = 0;
ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &val);
if (ret) {
dev_err(dev, "Failed to read headset type: %d\n", ret);
goto exit;
}
switch ((val & AIC31XX_HSD_TYPE_MASK) >>
AIC31XX_HSD_TYPE_SHIFT) {
case AIC31XX_HSD_HP:
status |= SND_JACK_HEADPHONE;
break;
case AIC31XX_HSD_HS:
status |= SND_JACK_HEADSET;
break;
default:
break;
}
if (aic31xx->jack)
snd_soc_jack_report(aic31xx->jack, status,
AIC31XX_JACK_MASK);
}
if (value & ~(AIC31XX_HPLSCDETECT |
AIC31XX_HPRSCDETECT))
AIC31XX_HPRSCDETECT |
AIC31XX_HSPLUG))
dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
read_overflow:
@ -1518,6 +1563,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
AIC31XX_HSPLUGDET |
AIC31XX_SC |
AIC31XX_ENGINE);

View File

@ -20,6 +20,9 @@
#define AIC31XX_MINIDSP_BIT BIT(2)
#define DAC31XX_BIT BIT(3)
#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
SND_JACK_HEADSET)
enum aic31xx_type {
AIC3100 = 0,
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
@ -220,6 +223,14 @@ struct aic31xx_pdata {
/* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
/* AIC31XX_HSDETECT */
#define AIC31XX_HSD_ENABLE BIT(7)
#define AIC31XX_HSD_TYPE_MASK GENMASK(6, 5)
#define AIC31XX_HSD_TYPE_SHIFT 5
#define AIC31XX_HSD_NONE 0x00
#define AIC31XX_HSD_HP 0x01
#define AIC31XX_HSD_HS 0x03
/* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
#define AIC31XX_MICBIAS_SHIFT 0