mirror of https://gitee.com/openkylin/linux.git
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:
parent
35146467bd
commit
ebf3326cd9
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue