aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0883-Enhances-the-DAC-driver-to-control-the-optional-head.patch
blob: 128906026d5d2bc5402501c941bdc83639f79733 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
From defa915bf0acf6ab5e56997a6733546c33f87682 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@i2audio.com>
Date: Tue, 7 Jul 2020 15:09:06 +0200
Subject: [PATCH] Enhances the DAC+ driver to control the optional
 headphone amplifier

Probes on the I2C bus for TPA6130A2, if successful, it sets DT-parameter
'status' from 'disabled' to 'okay' using change_sets to enable
the headphone control.

Signed-off-by: Joerg Schambacher joerg@i2audio.com
---
 sound/soc/bcm/Kconfig             |  1 +
 sound/soc/bcm/hifiberry_dacplus.c | 68 ++++++++++++++++++++++++++++++-
 2 files changed, 67 insertions(+), 2 deletions(-)

--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -38,6 +38,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
         tristate "Support for HifiBerry DAC+"
         depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
         select SND_SOC_PCM512x
+        select SND_SOC_TPA6130A2
         select COMMON_CLK_HIFIBERRY_DACPRO
         help
          Say Y or M if you want to add support for HifiBerry DAC+.
--- a/sound/soc/bcm/hifiberry_dacplus.c
+++ b/sound/soc/bcm/hifiberry_dacplus.c
@@ -4,6 +4,7 @@
  * Author:	Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
  *		Copyright 2014-2015
  *		based on code by Florian Meier <florian.meier@koalo.de>
+ *		Headphone added by Joerg Schambacher, joerg@i2audio.com
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/i2c.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -177,8 +179,7 @@ static int snd_rpi_hifiberry_dacplus_ini
 	else
 		snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
 
-	if (digital_gain_0db_limit)
-	{
+	if (digital_gain_0db_limit) {
 		int ret;
 		struct snd_soc_card *card = rtd->card;
 
@@ -292,6 +293,15 @@ static struct snd_soc_dai_link snd_rpi_h
 },
 };
 
+/* aux device for optional headphone amp */
+static struct snd_soc_aux_dev hifiberry_dacplus_aux_devs[] = {
+	{
+		.dlc = {
+			.name = "tpa6130a2.1-0060",
+		},
+	},
+};
+
 /* audio machine driver */
 static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
 	.name         = "snd_rpi_hifiberry_dacplus",
@@ -301,9 +311,63 @@ static struct snd_soc_card snd_rpi_hifib
 	.num_links    = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
 };
 
+static int hb_hp_detect(void)
+{
+	struct i2c_adapter *adap = i2c_get_adapter(1);
+	int ret;
+
+	struct i2c_client tpa_i2c_client = {
+		.addr = 0x60,
+		.adapter = adap,
+	};
+
+	ret = i2c_smbus_read_byte(&tpa_i2c_client) >= 0;
+	i2c_put_adapter(adap);
+	return ret;
+};
+
+static struct property tpa_enable_prop = {
+	       .name = "status",
+	       .length = 4 + 1, /* length 'okay' + 1 */
+	       .value = "okay",
+	};
+
 static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
 {
 	int ret = 0;
+	struct snd_soc_card *card = &snd_rpi_hifiberry_dacplus;
+	int len;
+	struct device_node *tpa_node;
+	struct property *tpa_prop;
+	struct of_changeset ocs;
+
+	/* probe for head phone amp */
+	if (hb_hp_detect()) {
+		card->aux_dev = hifiberry_dacplus_aux_devs;
+		card->num_aux_devs =
+				ARRAY_SIZE(hifiberry_dacplus_aux_devs);
+		tpa_node = of_find_compatible_node(NULL, NULL, "ti,tpa6130a2");
+		tpa_prop = of_find_property(tpa_node, "status", &len);
+
+		if (strcmp((char *)tpa_prop->value, "okay")) {
+			/* and activate headphone using change_sets */
+			dev_info(&pdev->dev, "activating headphone amplifier");
+			of_changeset_init(&ocs);
+			ret = of_changeset_update_property(&ocs, tpa_node,
+							&tpa_enable_prop);
+			if (ret) {
+				dev_err(&pdev->dev,
+				"cannot activate headphone amplifier\n");
+				return -ENODEV;
+			}
+			ret = of_changeset_apply(&ocs);
+			if (ret) {
+				dev_err(&pdev->dev,
+				"cannot activate headphone amplifier\n");
+				return -ENODEV;
+			}
+		}
+	}
 
 	snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
 	if (pdev->dev.of_node) {