Duncan Laurie | e8189b7 | 2020-04-29 12:09:32 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <acpi/acpigen.h> |
| 4 | #include <acpi/acpi_device.h> |
| 5 | #include <acpi/acpi_soundwire.h> |
| 6 | #include <commonlib/helpers.h> |
| 7 | #include <device/soundwire.h> |
Elyes HAOUAS | 5320f53 | 2020-07-10 10:26:33 +0200 | [diff] [blame] | 8 | #include <stddef.h> |
Duncan Laurie | e8189b7 | 2020-04-29 12:09:32 -0700 | [diff] [blame] | 9 | |
| 10 | /* Specification-defined prefix for SoundWire properties. */ |
| 11 | #define SDW_PFX "mipi-sdw-" |
| 12 | |
| 13 | /* Generate SoundWire property for integer. */ |
| 14 | #define SDW_INT(__key, __val) \ |
| 15 | acpi_dp_add_integer(dsd, SDW_PFX __key, __val) |
| 16 | |
| 17 | /* Generate SoundWire property for integer array. */ |
| 18 | #define SDW_INT_ARRAY(__key, __val) \ |
| 19 | acpi_dp_add_integer_array(dsd, SDW_PFX __key, __val, __val##_count) |
| 20 | |
| 21 | /** |
| 22 | * struct soundwire_name_map - Map ACPI name to SoundWire property name. |
| 23 | * @acpi_name: ACPI compatible name string. |
| 24 | * @sdw_name: MIPI SoundWire property name string. |
| 25 | */ |
| 26 | struct soundwire_name_map { |
| 27 | const char *acpi_name; |
| 28 | const char *sdw_name; |
| 29 | }; |
| 30 | |
| 31 | static const struct soundwire_name_map bra_mode_names[] = { |
| 32 | { "BRA0", SDW_PFX "port-bra-mode-0" }, |
| 33 | { "BRA1", SDW_PFX "port-bra-mode-1" }, |
| 34 | { "BRA2", SDW_PFX "port-bra-mode-2" }, |
| 35 | { "BRA3", SDW_PFX "port-bra-mode-3" }, |
| 36 | }; |
| 37 | |
| 38 | static const struct soundwire_name_map audio_mode_names[] = { |
| 39 | { "MOD0", SDW_PFX "port-audio-mode-0" }, |
| 40 | { "MOD1", SDW_PFX "port-audio-mode-1" }, |
| 41 | { "MOD2", SDW_PFX "port-audio-mode-2" }, |
| 42 | { "MOD3", SDW_PFX "port-audio-mode-3" }, |
| 43 | }; |
| 44 | |
| 45 | static const struct soundwire_name_map dpn_source_names[] = { |
| 46 | { "DP0", SDW_PFX "dp-0-subproperties" }, |
| 47 | { "SRC1", SDW_PFX "dp-1-source-subproperties" }, |
| 48 | { "SRC2", SDW_PFX "dp-2-source-subproperties" }, |
| 49 | { "SRC3", SDW_PFX "dp-3-source-subproperties" }, |
| 50 | { "SRC4", SDW_PFX "dp-4-source-subproperties" }, |
| 51 | { "SRC5", SDW_PFX "dp-5-source-subproperties" }, |
| 52 | { "SRC6", SDW_PFX "dp-6-source-subproperties" }, |
| 53 | { "SRC7", SDW_PFX "dp-7-source-subproperties" }, |
| 54 | { "SRC8", SDW_PFX "dp-8-source-subproperties" }, |
| 55 | { "SRC9", SDW_PFX "dp-9-source-subproperties" }, |
| 56 | { "SRCA", SDW_PFX "dp-10-source-subproperties" }, |
| 57 | { "SRCB", SDW_PFX "dp-11-source-subproperties" }, |
| 58 | { "SRCC", SDW_PFX "dp-12-source-subproperties" }, |
| 59 | { "SRCD", SDW_PFX "dp-13-source-subproperties" } |
| 60 | }; |
| 61 | |
| 62 | static const struct soundwire_name_map dpn_sink_names[] = { |
| 63 | { "DP0", SDW_PFX "dp-0-subproperties" }, |
| 64 | { "SNK1", SDW_PFX "dp-1-sink-subproperties" }, |
| 65 | { "SNK2", SDW_PFX "dp-2-sink-subproperties" }, |
| 66 | { "SNK3", SDW_PFX "dp-3-sink-subproperties" }, |
| 67 | { "SNK4", SDW_PFX "dp-4-sink-subproperties" }, |
| 68 | { "SNK5", SDW_PFX "dp-5-sink-subproperties" }, |
| 69 | { "SNK6", SDW_PFX "dp-6-sink-subproperties" }, |
| 70 | { "SNK7", SDW_PFX "dp-7-sink-subproperties" }, |
| 71 | { "SNK8", SDW_PFX "dp-8-sink-subproperties" }, |
| 72 | { "SNK9", SDW_PFX "dp-9-sink-subproperties" }, |
| 73 | { "SNKA", SDW_PFX "dp-10-sink-subproperties" }, |
| 74 | { "SNKB", SDW_PFX "dp-11-sink-subproperties" }, |
| 75 | { "SNKC", SDW_PFX "dp-12-sink-subproperties" }, |
| 76 | { "SNKD", SDW_PFX "dp-13-sink-subproperties" } |
| 77 | }; |
| 78 | |
| 79 | static const struct soundwire_name_map link_names[] = { |
| 80 | { "LNK0", SDW_PFX "link-0-subproperties" }, |
| 81 | { "LNK1", SDW_PFX "link-1-subproperties" }, |
| 82 | { "LNK2", SDW_PFX "link-2-subproperties" }, |
| 83 | { "LNK3", SDW_PFX "link-3-subproperties" }, |
| 84 | { "LNK4", SDW_PFX "link-4-subproperties" }, |
| 85 | { "LNK5", SDW_PFX "link-5-subproperties" }, |
| 86 | { "LNK6", SDW_PFX "link-6-subproperties" }, |
| 87 | { "LNK7", SDW_PFX "link-7-subproperties" } |
| 88 | }; |
| 89 | |
| 90 | static const char * const multilane_names[] = { |
| 91 | SDW_PFX "lane-1-mapping", |
| 92 | SDW_PFX "lane-2-mapping", |
| 93 | SDW_PFX "lane-3-mapping", |
| 94 | SDW_PFX "lane-4-mapping", |
| 95 | SDW_PFX "lane-5-mapping", |
| 96 | SDW_PFX "lane-6-mapping", |
| 97 | SDW_PFX "lane-7-mapping", |
| 98 | SDW_PFX "lane-8-mapping" |
| 99 | }; |
| 100 | |
| 101 | static const char * const multilane_master_lane_names[] = { |
| 102 | SDW_PFX "master-lane-1", |
| 103 | SDW_PFX "master-lane-2", |
| 104 | SDW_PFX "master-lane-3", |
| 105 | SDW_PFX "master-lane-4", |
| 106 | SDW_PFX "master-lane-5", |
| 107 | SDW_PFX "master-lane-6", |
| 108 | SDW_PFX "master-lane-7", |
| 109 | SDW_PFX "master-lane-8" |
| 110 | }; |
| 111 | |
| 112 | static const char * const multilane_slave_link_names[] = { |
| 113 | SDW_PFX "slave-link-A", |
| 114 | SDW_PFX "slave-link-B", |
| 115 | SDW_PFX "slave-link-C", |
| 116 | SDW_PFX "slave-link-D", |
| 117 | SDW_PFX "slave-link-E", |
| 118 | SDW_PFX "slave-link-F", |
| 119 | SDW_PFX "slave-link-G", |
| 120 | SDW_PFX "slave-link-I" |
| 121 | }; |
| 122 | |
| 123 | static const char * const multilane_bus_holder_names[] = { |
| 124 | SDW_PFX "lane-1-bus-holder", |
| 125 | SDW_PFX "lane-2-bus-holder", |
| 126 | SDW_PFX "lane-3-bus-holder", |
| 127 | SDW_PFX "lane-4-bus-holder", |
| 128 | SDW_PFX "lane-5-bus-holder", |
| 129 | SDW_PFX "lane-6-bus-holder", |
| 130 | SDW_PFX "lane-7-bus-holder", |
| 131 | SDW_PFX "lane-8-bus-holder" |
| 132 | }; |
| 133 | |
| 134 | static void soundwire_gen_interface_revision(struct acpi_dp *dsd) |
| 135 | { |
| 136 | acpi_dp_add_integer(dsd, SDW_PFX "sw-interface-revision", SOUNDWIRE_SW_VERSION_1_0); |
| 137 | } |
| 138 | |
| 139 | static void soundwire_gen_slave(struct acpi_dp *dsd, const struct soundwire_slave *prop) |
| 140 | { |
| 141 | soundwire_gen_interface_revision(dsd); |
| 142 | SDW_INT("wake-up-unavailable", prop->wake_up_unavailable); |
| 143 | SDW_INT("test-mode-supported", prop->test_mode_supported); |
| 144 | SDW_INT("clock-stop-mode1-supported", prop->clock_stop_mode1_supported); |
| 145 | |
| 146 | /* Clock Stop Prepare Timeout only used without simplified Clock Stop Prepare. */ |
| 147 | SDW_INT("simplified-clockstopprepare-sm-supported", |
| 148 | prop->simplified_clockstopprepare_sm_supported); |
| 149 | if (!prop->simplified_clockstopprepare_sm_supported) |
| 150 | SDW_INT("clockstopprepare-timeout", prop->clockstopprepare_timeout); |
| 151 | |
| 152 | SDW_INT("clockstopprepare-hard-reset-behavior", |
| 153 | prop->clockstopprepare_hard_reset_behavior); |
| 154 | SDW_INT("slave-channelprepare-timeout", prop->slave_channelprepare_timeout); |
| 155 | SDW_INT("highPHY-capable", prop->highPHY_capable); |
| 156 | SDW_INT("paging-supported", prop->paging_supported); |
| 157 | SDW_INT("bank-delay-supported", prop->bank_delay_supported); |
| 158 | SDW_INT("port15-read-behavior", prop->port15_read_behavior); |
| 159 | SDW_INT("master-count", prop->master_count); |
| 160 | SDW_INT("source-port-list", prop->source_port_list); |
| 161 | SDW_INT("sink-port-list", prop->sink_port_list); |
| 162 | } |
| 163 | |
| 164 | static void soundwire_gen_multilane(struct acpi_dp *dsd, const struct soundwire_multilane *prop) |
| 165 | { |
| 166 | size_t i; |
| 167 | |
| 168 | soundwire_gen_interface_revision(dsd); |
| 169 | |
| 170 | /* Fill out multilane map based on master/slave links. */ |
| 171 | for (i = 0; i < prop->lane_mapping_count && i < SOUNDWIRE_MAX_LANE; i++) { |
| 172 | const struct soundwire_multilane_map *map = &prop->lane_mapping[i]; |
| 173 | const char *name; |
| 174 | |
| 175 | /* Get the name of this connection */ |
| 176 | if (map->direction == MASTER_LANE) |
| 177 | name = multilane_master_lane_names[map->connection.master_lane]; |
| 178 | else |
| 179 | name = multilane_slave_link_names[map->connection.slave_link]; |
| 180 | |
| 181 | acpi_dp_add_string(dsd, multilane_names[map->lane], name); |
| 182 | } |
| 183 | |
| 184 | /* Add bus holder properties. */ |
| 185 | for (i = 0; i < prop->lane_bus_holder_count; i++) |
| 186 | acpi_dp_add_integer(dsd, multilane_bus_holder_names[i], |
| 187 | prop->lane_bus_holder[i]); |
| 188 | } |
| 189 | |
| 190 | static void soundwire_gen_link(struct acpi_dp *dsd, const struct soundwire_link *prop) |
| 191 | { |
| 192 | SDW_INT("clock-stop-mode0-supported", prop->clock_stop_mode0_supported); |
| 193 | SDW_INT("clock-stop-mode1-supported", prop->clock_stop_mode1_supported); |
| 194 | if (prop->clock_frequencies_supported_count > 0 && |
| 195 | prop->clock_frequencies_supported_count < SOUNDWIRE_MAX) { |
| 196 | SDW_INT_ARRAY("clock-frequencies-supported", |
| 197 | prop->clock_frequencies_supported); |
| 198 | } |
| 199 | SDW_INT("default-frame-rate", prop->default_frame_rate); |
| 200 | SDW_INT("default-frame-row-size", prop->default_frame_row_size); |
| 201 | SDW_INT("default-frame-col-size", prop->default_frame_col_size); |
| 202 | SDW_INT("dynamic-frame-shape", prop->dynamic_frame_shape); |
| 203 | SDW_INT("command-error-threshold", prop->command_error_threshold); |
| 204 | } |
| 205 | |
| 206 | static void soundwire_gen_bra_mode(struct acpi_dp *dsd, const struct soundwire_bra_mode *prop) |
| 207 | { |
| 208 | /* Bus frequency configs used if min/max not supported. */ |
| 209 | if (prop->bus_frequency_configs_count > 0 && |
| 210 | prop->bus_frequency_configs_count < SOUNDWIRE_MAX) { |
| 211 | SDW_INT_ARRAY("bra-mode-bus-frequency-configs", prop->bus_frequency_configs); |
| 212 | } else { |
| 213 | SDW_INT("bra-mode-min-bus-frequency", prop->min_bus_frequency); |
| 214 | SDW_INT("bra-mode-max-bus-frequency", prop->max_bus_frequency); |
| 215 | } |
| 216 | SDW_INT("bra-mode-max-data-per-frame", prop->max_data_per_frame); |
| 217 | SDW_INT("bra-mode-min-us-between-transactions", prop->min_us_between_transactions); |
| 218 | } |
| 219 | |
| 220 | static void soundwire_gen_audio_mode(struct acpi_dp *dsd, |
| 221 | const struct soundwire_audio_mode *prop) |
| 222 | { |
| 223 | /* Bus frequency configs used if min/max not supported. */ |
| 224 | if (prop->bus_frequency_configs_count > 0 && |
| 225 | prop->bus_frequency_configs_count < SOUNDWIRE_MAX) { |
| 226 | SDW_INT_ARRAY("audio-mode-bus-frequency-configs", prop->bus_frequency_configs); |
| 227 | } else { |
| 228 | SDW_INT("audio-mode-min-bus-frequency", prop->min_bus_frequency); |
| 229 | SDW_INT("audio-mode-max-bus-frequency", prop->max_bus_frequency); |
| 230 | } |
| 231 | |
| 232 | /* Sampling frequency configs used if min/max not supported. */ |
| 233 | if (prop->sampling_frequency_configs_count > 0 && |
| 234 | prop->sampling_frequency_configs_count < SOUNDWIRE_MAX) { |
| 235 | SDW_INT_ARRAY("audio-mode-sampling-frequency-configs", |
| 236 | prop->sampling_frequency_configs); |
| 237 | } else { |
| 238 | SDW_INT("audio-mode-max-sampling-frequency", prop->max_sampling_frequency); |
| 239 | SDW_INT("audio-mode-min-sampling-frequency", prop->min_sampling_frequency); |
| 240 | } |
| 241 | |
| 242 | SDW_INT("audio-mode-prepare-channel-behavior", prop->prepare_channel_behavior); |
| 243 | SDW_INT("audio-mode-glitchless-transitions", prop->glitchless_transitions); |
| 244 | } |
| 245 | |
| 246 | static void soundwire_gen_dp0(struct acpi_dp *dsd, const struct soundwire_dp0 *prop) |
| 247 | { |
| 248 | size_t i; |
| 249 | |
| 250 | /* Max wordlength configs used if min/max not supported. */ |
| 251 | if (prop->port_wordlength_configs_count > 0 && |
| 252 | prop->port_wordlength_configs_count < SOUNDWIRE_MAX) { |
| 253 | SDW_INT_ARRAY("port-wordlength-configs", prop->port_wordlength_configs); |
| 254 | } else { |
| 255 | SDW_INT("port-max-wordlength", prop->port_max_wordlength); |
| 256 | SDW_INT("port-min-wordlength", prop->port_min_wordlength); |
| 257 | } |
| 258 | SDW_INT("bra-flow-controlled", prop->bra_flow_controlled); |
| 259 | SDW_INT("bra-imp-def-response-supported", prop->bra_imp_def_response_supported); |
| 260 | SDW_INT("bra-role-supported", prop->bra_role_supported); |
| 261 | SDW_INT("simplified-channel-prepare-sm", prop->simplified_channel_prepare_sm); |
| 262 | SDW_INT("imp-def-dp0-interrupts-supported", prop->imp_def_dp0_interrupts_supported); |
| 263 | SDW_INT("imp-def-bpt-supported", prop->imp_def_bpt_supported); |
| 264 | |
| 265 | /* Add bulk register access mode property pointers. */ |
| 266 | for (i = 0; i < prop->bra_mode_count && i < SOUNDWIRE_MAX_MODE; i++) { |
| 267 | struct acpi_dp *bra = acpi_dp_new_table(bra_mode_names[i].acpi_name); |
| 268 | acpi_dp_add_child(dsd, bra_mode_names[i].sdw_name, bra); |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | static void soundwire_gen_dpn(struct acpi_dp *dsd, const struct soundwire_dpn *prop) |
| 273 | { |
| 274 | size_t i; |
| 275 | |
| 276 | SDW_INT("data-port-type", prop->data_port_type); |
| 277 | SDW_INT("max-grouping-supported", prop->max_grouping_supported); |
| 278 | SDW_INT("imp-def-dpn-interrupts-supported", prop->imp_def_dpn_interrupts_supported); |
| 279 | SDW_INT("modes-supported", prop->modes_supported); |
| 280 | SDW_INT("max-async-buffer", prop->max_async_buffer); |
| 281 | SDW_INT("block-packing-mode", prop->block_packing_mode); |
| 282 | SDW_INT("port-encoding-type", prop->port_encoding_type); |
| 283 | |
| 284 | /* Max wordlength configs used if min/max not supported. */ |
| 285 | if (prop->port_wordlength_configs_count > 0 && |
| 286 | prop->port_wordlength_configs_count < SOUNDWIRE_MAX) { |
| 287 | SDW_INT_ARRAY("port-wordlength-configs", prop->port_wordlength_configs); |
| 288 | } else { |
| 289 | SDW_INT("port-max-wordlength", prop->port_max_wordlength); |
| 290 | SDW_INT("port-min-wordlength", prop->port_min_wordlength); |
| 291 | } |
| 292 | |
| 293 | /* Channel Prepare Timeout only used without simplified Channel Prepare. */ |
| 294 | SDW_INT("simplified-channelprepare-sm", prop->simplified_channelprepare_sm); |
| 295 | if (!prop->simplified_channelprepare_sm) |
| 296 | SDW_INT("port-channelprepare-timeout", prop->port_channelprepare_timeout); |
| 297 | |
| 298 | /* Channel number list used if min/max not supported. */ |
| 299 | if (prop->channel_number_list_count > 0 && |
| 300 | prop->channel_number_list_count < SOUNDWIRE_MAX) { |
| 301 | SDW_INT_ARRAY("channel-number-list", prop->channel_number_list); |
| 302 | } else { |
| 303 | SDW_INT("min-channel-number", prop->min_channel_number); |
| 304 | SDW_INT("max-channel-number", prop->max_channel_number); |
| 305 | } |
| 306 | if (prop->channel_combination_list_count > 0 && |
| 307 | prop->channel_combination_list_count < SOUNDWIRE_MAX) { |
| 308 | SDW_INT_ARRAY("channel-combination-list", prop->channel_combination_list); |
| 309 | } |
| 310 | |
| 311 | /* Add reference to Audio Mode properties. */ |
| 312 | for (i = 0; i < prop->port_audio_mode_count && i < SOUNDWIRE_MAX_MODE; i++) { |
| 313 | struct acpi_dp *am = acpi_dp_new_table(audio_mode_names[i].acpi_name); |
| 314 | acpi_dp_add_child(dsd, audio_mode_names[i].sdw_name, am); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | void soundwire_gen_controller(struct acpi_dp *dsd, const struct soundwire_controller *prop, |
| 319 | soundwire_link_prop_cb link_prop_cb) |
| 320 | { |
| 321 | size_t i; |
| 322 | |
| 323 | soundwire_gen_interface_revision(dsd); |
| 324 | SDW_INT("master-count", prop->master_list_count); |
| 325 | |
| 326 | /* Generate properties for each master link on the controller. */ |
| 327 | for (i = 0; i < prop->master_list_count && i < SOUNDWIRE_MAX_LINK; i++) { |
| 328 | struct acpi_dp *link = acpi_dp_new_table(link_names[i].acpi_name); |
| 329 | soundwire_gen_link(link, &prop->master_list[i]); |
| 330 | |
| 331 | /* Callback for custom link properties from the controller. */ |
| 332 | if (link_prop_cb) |
| 333 | link_prop_cb(link, i, prop); |
| 334 | acpi_dp_add_child(dsd, link_names[i].sdw_name, link); |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | void soundwire_gen_codec(struct acpi_dp *dsd, const struct soundwire_codec *codec, |
| 339 | soundwire_dp_prop_cb dp_prop_cb) |
| 340 | { |
| 341 | const struct soundwire_dpn_entry *entry; |
| 342 | const struct soundwire_name_map *name; |
| 343 | size_t i; |
| 344 | |
| 345 | /* Generate slave properties for this codec. */ |
| 346 | soundwire_gen_slave(dsd, codec->slave); |
| 347 | |
| 348 | /* Generate properties for multilane config, if provided. */ |
| 349 | if (codec->multilane) |
| 350 | soundwire_gen_multilane(dsd, codec->multilane); |
| 351 | |
| 352 | /* Generate properties for data port 0, if provided. */ |
| 353 | if (codec->dp0) { |
| 354 | struct acpi_dp *dp0; |
| 355 | |
| 356 | /* First generate any Bulk Register Access mode properties. */ |
| 357 | for (i = 0; i < SOUNDWIRE_MAX_MODE; i++) { |
| 358 | const struct soundwire_bra_mode *prop = codec->dp0_bra_mode[i]; |
| 359 | struct acpi_dp *bra; |
| 360 | |
| 361 | /* Stop processing at the first undefined BRA mode. */ |
| 362 | if (!prop) |
| 363 | break; |
| 364 | name = &bra_mode_names[i]; |
| 365 | bra = acpi_dp_new_table(name->acpi_name); |
| 366 | soundwire_gen_bra_mode(bra, prop); |
| 367 | acpi_dp_add_child(dsd, name->sdw_name, bra); |
| 368 | } |
| 369 | |
| 370 | name = &dpn_source_names[0]; |
| 371 | dp0 = acpi_dp_new_table(name->acpi_name); |
| 372 | soundwire_gen_dp0(dp0, codec->dp0); |
| 373 | |
| 374 | /* Callback for custom properties from the codec. */ |
| 375 | if (dp_prop_cb) |
| 376 | dp_prop_cb(dp0, 0, codec); |
| 377 | acpi_dp_add_child(dsd, name->sdw_name, dp0); |
| 378 | } |
| 379 | |
| 380 | /* |
| 381 | * First generate audio modes for the data ports. This results in unnecessary |
| 382 | * (but harmless) references to the audio modes at the codec level, but it allows |
| 383 | * the data ports to use these objects without duplication. |
| 384 | */ |
| 385 | for (i = 0; i < SOUNDWIRE_MAX_MODE; i++) { |
| 386 | const struct soundwire_audio_mode *prop = codec->audio_mode[i]; |
| 387 | struct acpi_dp *am; |
| 388 | |
| 389 | /* Stop processing at the first undefined audio mode. */ |
| 390 | if (!prop) |
| 391 | break; |
| 392 | name = &audio_mode_names[i]; |
| 393 | am = acpi_dp_new_table(name->acpi_name); |
| 394 | soundwire_gen_audio_mode(am, prop); |
| 395 | acpi_dp_add_child(dsd, name->sdw_name, am); |
| 396 | } |
| 397 | |
| 398 | /* Now generate properties for source/slave on each defined data port. */ |
| 399 | for (entry = codec->dpn; entry; entry++) { |
| 400 | struct acpi_dp *dpn; |
| 401 | |
| 402 | /* Stop processing at the first invalid data port. */ |
| 403 | if (entry->port < SOUNDWIRE_MIN_DPN || entry->port > SOUNDWIRE_MAX_DPN) |
| 404 | break; |
| 405 | |
| 406 | if (entry->source) { |
| 407 | name = &dpn_source_names[entry->port]; |
| 408 | dpn = acpi_dp_new_table(name->acpi_name); |
| 409 | soundwire_gen_dpn(dpn, entry->source); |
| 410 | |
| 411 | /* Callback for custom properties from the codec. */ |
| 412 | if (dp_prop_cb) |
| 413 | dp_prop_cb(dpn, entry->port, codec); |
| 414 | acpi_dp_add_child(dsd, name->sdw_name, dpn); |
| 415 | } |
| 416 | if (entry->sink) { |
| 417 | name = &dpn_sink_names[entry->port]; |
| 418 | dpn = acpi_dp_new_table(name->acpi_name); |
| 419 | soundwire_gen_dpn(dpn, entry->sink); |
| 420 | |
| 421 | /* Callback for custom properties from the codec. */ |
| 422 | if (dp_prop_cb) |
| 423 | dp_prop_cb(dpn, entry->port, codec); |
| 424 | acpi_dp_add_child(dsd, name->sdw_name, dpn); |
| 425 | } |
| 426 | } |
| 427 | } |