summarylogtreecommitdiffstats
path: root/0001-Cirrus-no-dsdt.patch
blob: 8de56f9d3a69ec10d0b3a301812606b73f88c436 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
From git@z Thu Jan  1 00:00:00 1970
Subject: [PATCH v1] ALSA: hda: cs35l41: Support systems with missing _DSD
 properties
From: Stefan Binding <sbinding@opensource.cirrus.com>
Date: Tue, 15 Aug 2023 17:10:33 +0100
Message-Id: <20230815161033.3519-1-sbinding@opensource.cirrus.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit

Some systems using CS35L41 with HDA were released without some
required _DSD properties in ACPI. To support these special cases,
add an api to configure the correct properties for systems with
this issue.

This initial commit moves the no _DSD support for Lenovo
Legion Laptops (CLSA0100, CLSA0101) into a new framework which
can be extended to support additional laptops in the future.

Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
---
 sound/pci/hda/Makefile               |  2 +-
 sound/pci/hda/cs35l41_hda.c          | 65 ++++++-------------------
 sound/pci/hda/cs35l41_hda.h          |  1 +
 sound/pci/hda/cs35l41_hda_property.c | 73 ++++++++++++++++++++++++++++
 sound/pci/hda/cs35l41_hda_property.h | 18 +++++++
 5 files changed, 108 insertions(+), 51 deletions(-)
 create mode 100644 sound/pci/hda/cs35l41_hda_property.c
 create mode 100644 sound/pci/hda/cs35l41_hda_property.h

diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index c6e6509e7b8e..5506255be895 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -28,7 +28,7 @@ snd-hda-codec-via-objs :=	patch_via.o
 snd-hda-codec-hdmi-objs :=	patch_hdmi.o hda_eld.o
 
 # side codecs
-snd-hda-scodec-cs35l41-objs :=		cs35l41_hda.o
+snd-hda-scodec-cs35l41-objs :=		cs35l41_hda.o cs35l41_hda_property.o
 snd-hda-scodec-cs35l41-i2c-objs :=	cs35l41_hda_i2c.o
 snd-hda-scodec-cs35l41-spi-objs :=	cs35l41_hda_spi.o
 snd-hda-scodec-cs35l56-objs :=		cs35l56_hda.o
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 825e551be9bb..f9b77353c266 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -19,6 +19,7 @@
 #include "hda_component.h"
 #include "cs35l41_hda.h"
 #include "hda_cs_dsp_ctl.h"
+#include "cs35l41_hda_property.h"
 
 #define CS35L41_FIRMWARE_ROOT "cirrus/"
 #define CS35L41_PART "cs35l41"
@@ -1315,8 +1316,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
 	return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
 }
 
-static int cs35l41_get_speaker_id(struct device *dev, int amp_index,
-				  int num_amps, int fixed_gpio_id)
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)
 {
 	struct gpio_desc *speaker_id_desc;
 	int speaker_id = -ENODEV;
@@ -1370,49 +1370,6 @@ static int cs35l41_get_speaker_id(struct device *dev, int amp_index,
 	return speaker_id;
 }
 
-/*
- * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
- * And devices created by serial-multi-instantiate don't have their device struct
- * pointing to the correct fwnode, so acpi_dev must be used here.
- * And devm functions expect that the device requesting the resource has the correct
- * fwnode.
- */
-static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-			       const char *hid)
-{
-	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-
-	/* check I2C address to assign the index */
-	cs35l41->index = id == 0x40 ? 0 : 1;
-	cs35l41->channel_index = 0;
-	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
-	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
-	hw_cfg->spk_pos = cs35l41->index;
-	hw_cfg->gpio2.func = CS35L41_INTERRUPT;
-	hw_cfg->gpio2.valid = true;
-	hw_cfg->valid = true;
-
-	if (strncmp(hid, "CLSA0100", 8) == 0) {
-		hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
-	} else if (strncmp(hid, "CLSA0101", 8) == 0) {
-		hw_cfg->bst_type = CS35L41_EXT_BOOST;
-		hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
-		hw_cfg->gpio1.valid = true;
-	} else {
-		/*
-		 * Note: CLSA010(0/1) are special cases which use a slightly different design.
-		 * All other HIDs e.g. CSC3551 require valid ACPI _DSD properties to be supported.
-		 */
-		dev_err(cs35l41->dev, "Error: ACPI _DSD Properties are missing for HID %s.\n", hid);
-		hw_cfg->valid = false;
-		hw_cfg->gpio1.valid = false;
-		hw_cfg->gpio2.valid = false;
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
 {
 	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
@@ -1438,12 +1395,17 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
 		sub = NULL;
 	cs35l41->acpi_subsystem_id = sub;
 
+	ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
+	if (!ret) {
+		dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
+		goto put_physdev;
+	}
+
 	property = "cirrus,dev-index";
 	ret = device_property_count_u32(physdev, property);
-	if (ret <= 0) {
-		ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
-		goto err_put_physdev;
-	}
+	if (ret <= 0)
+		goto err;
+
 	if (ret > ARRAY_SIZE(values)) {
 		ret = -EINVAL;
 		goto err;
@@ -1533,7 +1495,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
 
 err:
 	dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
-err_put_physdev:
+	hw_cfg->valid = false;
+	hw_cfg->gpio1.valid = false;
+	hw_cfg->gpio2.valid = false;
+put_physdev:
 	put_device(physdev);
 
 	return ret;
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h
index bdb35f3be68a..b93bf762976e 100644
--- a/sound/pci/hda/cs35l41_hda.h
+++ b/sound/pci/hda/cs35l41_hda.h
@@ -83,5 +83,6 @@ extern const struct dev_pm_ops cs35l41_hda_pm_ops;
 int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
 		      struct regmap *regmap);
 void cs35l41_hda_remove(struct device *dev);
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);
 
 #endif /*__CS35L41_HDA_H__*/
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
new file mode 100644
index 000000000000..673f23257a09
--- /dev/null
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35L41 ALSA HDA Property driver
+//
+// Copyright 2023 Cirrus Logic, Inc.
+//
+// Author: Stefan Binding <sbinding@opensource.cirrus.com>
+
+#include <linux/gpio/consumer.h>
+#include <linux/string.h>
+#include "cs35l41_hda_property.h"
+
+/*
+ * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
+ * And devices created by serial-multi-instantiate don't have their device struct
+ * pointing to the correct fwnode, so acpi_dev must be used here.
+ * And devm functions expect that the device requesting the resource has the correct
+ * fwnode.
+ */
+static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+				 const char *hid)
+{
+	struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+	/* check I2C address to assign the index */
+	cs35l41->index = id == 0x40 ? 0 : 1;
+	cs35l41->channel_index = 0;
+	cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+	cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+	hw_cfg->spk_pos = cs35l41->index;
+	hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+	hw_cfg->gpio2.valid = true;
+	hw_cfg->valid = true;
+
+	if (strcmp(hid, "CLSA0100") == 0) {
+		hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
+	} else if (strcmp(hid, "CLSA0101") == 0) {
+		hw_cfg->bst_type = CS35L41_EXT_BOOST;
+		hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+		hw_cfg->gpio1.valid = true;
+	}
+
+	return 0;
+}
+
+struct cs35l41_prop_model {
+	const char *hid;
+	const char *ssid;
+	int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+			const char *hid);
+};
+
+const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
+	{ "CLSA0100", NULL, lenovo_legion_no_acpi },
+	{ "CLSA0101", NULL, lenovo_legion_no_acpi },
+	{}
+};
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+			       const char *hid)
+{
+	const struct cs35l41_prop_model *model;
+
+	for (model = cs35l41_prop_model_table; model->hid > 0; model++) {
+		if (!strcmp(model->hid, hid) &&
+		    (!model->ssid ||
+		     (cs35l41->acpi_subsystem_id &&
+		      !strcmp(model->ssid, cs35l41->acpi_subsystem_id))))
+			return model->add_prop(cs35l41, physdev, id, hid);
+	}
+
+	return -ENOENT;
+}
diff --git a/sound/pci/hda/cs35l41_hda_property.h b/sound/pci/hda/cs35l41_hda_property.h
new file mode 100644
index 000000000000..fd834042e2fd
--- /dev/null
+++ b/sound/pci/hda/cs35l41_hda_property.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * CS35L41 ALSA HDA Property driver
+ *
+ * Copyright 2023 Cirrus Logic, Inc.
+ *
+ * Author: Stefan Binding <sbinding@opensource.cirrus.com>
+ */
+
+#ifndef CS35L41_HDA_PROP_H
+#define CS35L41_HDA_PROP_H
+
+#include <linux/device.h>
+#include "cs35l41_hda.h"
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+			       const char *hid);
+#endif /* CS35L41_HDA_PROP_H */
-- 
2.34.1