[v2,18/19] ASoC: tlv320aic31xx: Add headphone/headset detection
diff mbox

Message ID 20171129213300.20021-19-afd@ti.com
State New
Headers show

Commit Message

Andrew F. Davis Nov. 29, 2017, 9:32 p.m. UTC
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>
---
 sound/soc/codecs/tlv320aic31xx.c | 33 +++++++++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic31xx.h | 11 +++++++++++
 2 files changed, 44 insertions(+)

Comments

Mark Brown Dec. 1, 2017, 1:41 p.m. UTC | #1
On Wed, Nov 29, 2017 at 03:32:59PM -0600, Andrew F. Davis wrote:
> 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.

This only does half the job, there's no way for anything to specify a
jack here.
Andrew F. Davis Dec. 6, 2017, 5:25 p.m. UTC | #2
On 12/01/2017 07:41 AM, Mark Brown wrote:
> On Wed, Nov 29, 2017 at 03:32:59PM -0600, Andrew F. Davis wrote:
>> 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.
> 
> This only does half the job, there's no way for anything to specify a
> jack here.
> 

Other CODECs drivers expose some kind of platform/machine specific
function(s) to send the jack definition to the CODEC, we seem to be
missing a generic way to report jack information up to the machine layer
driver.

Perhaps a struct with a jack enable/disable and call-back functions
could be created when registering the codec/platform component driver?
Then machines can hook to this as they need?
Mark Brown Dec. 6, 2017, 5:32 p.m. UTC | #3
On Wed, Dec 06, 2017 at 11:25:15AM -0600, Andrew F. Davis wrote:
> On 12/01/2017 07:41 AM, Mark Brown wrote:

> > This only does half the job, there's no way for anything to specify a
> > jack here.

> Other CODECs drivers expose some kind of platform/machine specific
> function(s) to send the jack definition to the CODEC, we seem to be

Your driver doesn't do that.

> missing a generic way to report jack information up to the machine layer
> driver.

snd_soc_codec_set_jack()
Andrew F. Davis Dec. 6, 2017, 5:47 p.m. UTC | #4
On 12/06/2017 11:32 AM, Mark Brown wrote:
> On Wed, Dec 06, 2017 at 11:25:15AM -0600, Andrew F. Davis wrote:
>> On 12/01/2017 07:41 AM, Mark Brown wrote:
> 
>>> This only does half the job, there's no way for anything to specify a
>>> jack here.
> 
>> Other CODECs drivers expose some kind of platform/machine specific
>> function(s) to send the jack definition to the CODEC, we seem to be
> 
> Your driver doesn't do that.
> 

Right, I don't have a specific machine in mind so didn't wan to do it
that way.

>> missing a generic way to report jack information up to the machine layer
>> driver.
> 
> snd_soc_codec_set_jack()
> 

Hmm, this looks close to what I was thinking (I was wanting to go the
other direction and have the codec report what jacks it supports, this
could allow for more than one jack), I'll see if I can make it work.
Mark Brown Dec. 6, 2017, 5:52 p.m. UTC | #5
On Wed, Dec 06, 2017 at 11:47:14AM -0600, Andrew F. Davis wrote:
> On 12/06/2017 11:32 AM, Mark Brown wrote:

> >> missing a generic way to report jack information up to the machine layer
> >> driver.

> > snd_soc_codec_set_jack()

> Hmm, this looks close to what I was thinking (I was wanting to go the
> other direction and have the codec report what jacks it supports, this
> could allow for more than one jack), I'll see if I can make it work.

Almost always the CODEC requires some extra connections in order to
enable jack detection features, these are going to be board specific so
they come from the machine driver.

Patch
diff mbox

diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 094b1596f9cc..471b31be55d1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -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;
@@ -161,6 +163,7 @@  struct aic31xx_priv {
 	struct gpio_desc *gpio_reset;
 	int micbias_vg;
 	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+	struct snd_soc_jack *jack;
 	unsigned int sysclk;
 	u8 p_div;
 	int rate_div_line;
@@ -1277,6 +1280,32 @@  static irqreturn_t aic31xx_irq(int irq, void *data)
 	if (value & AIC31XX_HPRSCDETECT)
 		dev_err(dev, "Short circuit on Right output is detected\n");
 
+	if (value & AIC31XX_HSPLUG) {
+		int status = 0;
+
+		ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &value);
+		if (ret) {
+			dev_err(dev, "Failed to read headset type: %d\n", ret);
+			return IRQ_NONE;
+		}
+
+		switch ((value & 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);
+	}
+
 	ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
 	if (ret) {
 		dev_err(dev, "Failed to read overflow flag: %d\n", ret);
@@ -1365,9 +1394,13 @@  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);
 
+		regmap_write(aic31xx->regmap, AIC31XX_HSDETECT,
+			     AIC31XX_HSD_ENABLE);
+
 		ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
 						NULL, aic31xx_irq,
 						IRQF_ONESHOT, "aic31xx-irq",
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index d062663f66b5..66c85df4d5be 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -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,
@@ -213,6 +216,14 @@  enum aic31xx_type {
 /* 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