Commit ebf3326c authored by Andrew F. Davis's avatar Andrew F. Davis Committed by Mark Brown

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: default avatarAndrew F. Davis <afd@ti.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 35146467
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
...@@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg) ...@@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg)
case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */ case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
case AIC31XX_INTRDACFLAG2: case AIC31XX_INTRDACFLAG2:
case AIC31XX_INTRADCFLAG2: case AIC31XX_INTRADCFLAG2:
case AIC31XX_HSDETECT:
return true; return true;
} }
return false; return false;
...@@ -163,6 +165,7 @@ struct aic31xx_priv { ...@@ -163,6 +165,7 @@ struct aic31xx_priv {
struct aic31xx_pdata pdata; struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
struct snd_soc_jack *jack;
unsigned int sysclk; unsigned int sysclk;
u8 p_div; u8 p_div;
int rate_div_line; int rate_div_line;
...@@ -1261,6 +1264,20 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component, ...@@ -1261,6 +1264,20 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component,
return 0; 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) static int aic31xx_codec_probe(struct snd_soc_component *component)
{ {
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(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) ...@@ -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 = { static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe, .probe = aic31xx_codec_probe,
.set_jack = aic31xx_set_jack,
.set_bias_level = aic31xx_set_bias_level, .set_bias_level = aic31xx_set_bias_level,
.controls = common31xx_snd_controls, .controls = common31xx_snd_controls,
.num_controls = ARRAY_SIZE(common31xx_snd_controls), .num_controls = ARRAY_SIZE(common31xx_snd_controls),
...@@ -1405,8 +1423,35 @@ static irqreturn_t aic31xx_irq(int irq, void *data) ...@@ -1405,8 +1423,35 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
dev_err(dev, "Short circuit on Left output is detected\n"); dev_err(dev, "Short circuit on Left output is detected\n");
if (value & AIC31XX_HPRSCDETECT) if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n"); 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 | if (value & ~(AIC31XX_HPLSCDETECT |
AIC31XX_HPRSCDETECT)) AIC31XX_HPRSCDETECT |
AIC31XX_HSPLUG))
dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
read_overflow: read_overflow:
...@@ -1518,6 +1563,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ...@@ -1518,6 +1563,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
AIC31XX_GPIO1_FUNC_SHIFT); AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
AIC31XX_HSPLUGDET |
AIC31XX_SC | AIC31XX_SC |
AIC31XX_ENGINE); AIC31XX_ENGINE);
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#define AIC31XX_MINIDSP_BIT BIT(2) #define AIC31XX_MINIDSP_BIT BIT(2)
#define DAC31XX_BIT BIT(3) #define DAC31XX_BIT BIT(3)
#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
SND_JACK_HEADSET)
enum aic31xx_type { enum aic31xx_type {
AIC3100 = 0, AIC3100 = 0,
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
...@@ -220,6 +223,14 @@ struct aic31xx_pdata { ...@@ -220,6 +223,14 @@ struct aic31xx_pdata {
/* AIC31XX_DACMUTE */ /* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2) #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 */ /* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK GENMASK(1, 0) #define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
#define AIC31XX_MICBIAS_SHIFT 0 #define AIC31XX_MICBIAS_SHIFT 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment