16
16
#include <linux/i2c.h>
17
17
#include <linux/mod_devicetable.h>
18
18
#include <linux/module.h>
19
+ #include <linux/pci_ids.h>
19
20
#include <linux/pm_runtime.h>
20
21
#include <linux/regmap.h>
21
22
#include <sound/hda_codec.h>
@@ -110,10 +111,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
110
111
return 1 ;
111
112
}
112
113
114
+ static const struct acpi_gpio_params speakerid_gpios = { 0 , 0 , false };
115
+
116
+ static const struct acpi_gpio_mapping tas2781_speaker_id_gpios [] = {
117
+ { "speakerid-gpios" , & speakerid_gpios , 1 },
118
+ { }
119
+ };
120
+
113
121
static int tas2781_read_acpi (struct tasdevice_priv * p , const char * hid )
114
122
{
115
123
struct acpi_device * adev ;
124
+ struct device * physdev ;
116
125
LIST_HEAD (resources );
126
+ const char * sub ;
127
+ uint32_t subid ;
117
128
int ret ;
118
129
119
130
adev = acpi_dev_get_first_match_dev (hid , NULL , -1 );
@@ -123,18 +134,45 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
123
134
return - ENODEV ;
124
135
}
125
136
137
+ physdev = get_device (acpi_get_first_physical_node (adev ));
126
138
ret = acpi_dev_get_resources (adev , & resources , tas2781_get_i2c_res , p );
127
- if (ret < 0 )
139
+ if (ret < 0 ) {
140
+ dev_err (p -> dev , "Failed to get ACPI resource.\n" );
141
+ goto err ;
142
+ }
143
+ sub = acpi_get_subsystem_id (ACPI_HANDLE (physdev ));
144
+ if (IS_ERR (sub )) {
145
+ dev_err (p -> dev , "Failed to get SUBSYS ID.\n" );
128
146
goto err ;
147
+ }
148
+ /* Speaker id was needed for ASUS projects. */
149
+ ret = kstrtou32 (sub , 16 , & subid );
150
+ if (!ret && upper_16_bits (subid ) == PCI_VENDOR_ID_ASUSTEK ) {
151
+ ret = devm_acpi_dev_add_driver_gpios (p -> dev ,
152
+ tas2781_speaker_id_gpios );
153
+ if (ret < 0 )
154
+ dev_err (p -> dev , "Failed to add driver gpio %d.\n" ,
155
+ ret );
156
+ p -> speaker_id = devm_gpiod_get (p -> dev , "speakerid" , GPIOD_IN );
157
+ if (IS_ERR (p -> speaker_id )) {
158
+ dev_err (p -> dev , "Failed to get Speaker id.\n" );
159
+ ret = PTR_ERR (p -> speaker_id );
160
+ goto err ;
161
+ }
162
+ } else {
163
+ p -> speaker_id = NULL ;
164
+ }
129
165
130
166
acpi_dev_free_resource_list (& resources );
131
167
strscpy (p -> dev_name , hid , sizeof (p -> dev_name ));
168
+ put_device (physdev );
132
169
acpi_dev_put (adev );
133
170
134
171
return 0 ;
135
172
136
173
err :
137
174
dev_err (p -> dev , "read acpi error, ret: %d\n" , ret );
175
+ put_device (physdev );
138
176
acpi_dev_put (adev );
139
177
140
178
return ret ;
@@ -615,7 +653,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
615
653
struct tasdevice_priv * tas_priv = context ;
616
654
struct tas2781_hda * tas_hda = dev_get_drvdata (tas_priv -> dev );
617
655
struct hda_codec * codec = tas_priv -> codec ;
618
- int i , ret ;
656
+ int i , ret , spk_id ;
619
657
620
658
pm_runtime_get_sync (tas_priv -> dev );
621
659
mutex_lock (& tas_priv -> codec_lock );
@@ -648,8 +686,25 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
648
686
tasdevice_dsp_remove (tas_priv );
649
687
650
688
tas_priv -> fw_state = TASDEVICE_DSP_FW_PENDING ;
651
- scnprintf (tas_priv -> coef_binaryname , 64 , "TAS2XXX%04X.bin" ,
652
- codec -> core .subsystem_id & 0xffff );
689
+ if (tas_priv -> speaker_id != NULL ) {
690
+ // Speaker id need to be checked for ASUS only.
691
+ spk_id = gpiod_get_value (tas_priv -> speaker_id );
692
+ if (spk_id < 0 ) {
693
+ // Speaker id is not valid, use default.
694
+ dev_dbg (tas_priv -> dev , "Wrong spk_id = %d\n" , spk_id );
695
+ spk_id = 0 ;
696
+ }
697
+ snprintf (tas_priv -> coef_binaryname ,
698
+ sizeof (tas_priv -> coef_binaryname ),
699
+ "TAS2XXX%04X%d.bin" ,
700
+ lower_16_bits (codec -> core .subsystem_id ),
701
+ spk_id );
702
+ } else {
703
+ snprintf (tas_priv -> coef_binaryname ,
704
+ sizeof (tas_priv -> coef_binaryname ),
705
+ "TAS2XXX%04X.bin" ,
706
+ lower_16_bits (codec -> core .subsystem_id ));
707
+ }
653
708
ret = tasdevice_dsp_parser (tas_priv );
654
709
if (ret ) {
655
710
dev_err (tas_priv -> dev , "dspfw load %s error\n" ,
0 commit comments