soc-acpi.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // soc-apci.c - support for ACPI enumeration.
  4. //
  5. // Copyright (c) 2013-15, Intel Corporation.
  6. #include <linux/export.h>
  7. #include <linux/module.h>
  8. #include <sound/soc-acpi.h>
  9. static bool snd_soc_acpi_id_present(struct snd_soc_acpi_mach *machine)
  10. {
  11. const struct snd_soc_acpi_codecs *comp_ids = machine->comp_ids;
  12. int i;
  13. if (machine->id[0]) {
  14. if (acpi_dev_present(machine->id, NULL, -1))
  15. return true;
  16. }
  17. if (comp_ids) {
  18. for (i = 0; i < comp_ids->num_codecs; i++) {
  19. if (acpi_dev_present(comp_ids->codecs[i], NULL, -1)) {
  20. strscpy(machine->id, comp_ids->codecs[i], ACPI_ID_LEN);
  21. return true;
  22. }
  23. }
  24. }
  25. return false;
  26. }
  27. struct snd_soc_acpi_mach *
  28. snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
  29. {
  30. struct snd_soc_acpi_mach *mach;
  31. struct snd_soc_acpi_mach *mach_alt;
  32. for (mach = machines; mach->id[0] || mach->comp_ids; mach++) {
  33. if (snd_soc_acpi_id_present(mach)) {
  34. if (mach->machine_quirk) {
  35. mach_alt = mach->machine_quirk(mach);
  36. if (!mach_alt)
  37. continue; /* not full match, ignore */
  38. mach = mach_alt;
  39. }
  40. return mach;
  41. }
  42. }
  43. return NULL;
  44. }
  45. EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
  46. static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
  47. void *context, void **ret)
  48. {
  49. struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
  50. acpi_status status;
  51. struct snd_soc_acpi_package_context *pkg_ctx = context;
  52. pkg_ctx->data_valid = false;
  53. if (adev && adev->status.present && adev->status.functional) {
  54. struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
  55. union acpi_object *myobj = NULL;
  56. status = acpi_evaluate_object_typed(handle, pkg_ctx->name,
  57. NULL, &buffer,
  58. ACPI_TYPE_PACKAGE);
  59. if (ACPI_FAILURE(status))
  60. return AE_OK;
  61. myobj = buffer.pointer;
  62. if (!myobj || myobj->package.count != pkg_ctx->length) {
  63. kfree(buffer.pointer);
  64. return AE_OK;
  65. }
  66. status = acpi_extract_package(myobj,
  67. pkg_ctx->format, pkg_ctx->state);
  68. if (ACPI_FAILURE(status)) {
  69. kfree(buffer.pointer);
  70. return AE_OK;
  71. }
  72. kfree(buffer.pointer);
  73. pkg_ctx->data_valid = true;
  74. return AE_CTRL_TERMINATE;
  75. }
  76. return AE_OK;
  77. }
  78. bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
  79. struct snd_soc_acpi_package_context *ctx)
  80. {
  81. acpi_status status;
  82. status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL);
  83. if (ACPI_FAILURE(status) || !ctx->data_valid)
  84. return false;
  85. return true;
  86. }
  87. EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid);
  88. struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
  89. {
  90. struct snd_soc_acpi_mach *mach = arg;
  91. struct snd_soc_acpi_codecs *codec_list =
  92. (struct snd_soc_acpi_codecs *) mach->quirk_data;
  93. int i;
  94. if (mach->quirk_data == NULL)
  95. return mach;
  96. for (i = 0; i < codec_list->num_codecs; i++) {
  97. if (!acpi_dev_present(codec_list->codecs[i], NULL, -1))
  98. return NULL;
  99. }
  100. return mach;
  101. }
  102. EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
  103. #define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
  104. SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
  105. /* Check if all Slaves defined on the link can be found */
  106. bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
  107. const struct snd_soc_acpi_link_adr *link,
  108. struct sdw_extended_slave_id *ids,
  109. int num_slaves)
  110. {
  111. unsigned int part_id, link_id, unique_id, mfg_id, version;
  112. int i, j, k;
  113. for (i = 0; i < link->num_adr; i++) {
  114. u64 adr = link->adr_d[i].adr;
  115. int reported_part_count = 0;
  116. mfg_id = SDW_MFG_ID(adr);
  117. part_id = SDW_PART_ID(adr);
  118. link_id = SDW_DISCO_LINK_ID(adr);
  119. version = SDW_VERSION(adr);
  120. for (j = 0; j < num_slaves; j++) {
  121. /* find out how many identical parts were reported on that link */
  122. if (ids[j].link_id == link_id &&
  123. ids[j].id.part_id == part_id &&
  124. ids[j].id.mfg_id == mfg_id &&
  125. ids[j].id.sdw_version == version)
  126. reported_part_count++;
  127. }
  128. for (j = 0; j < num_slaves; j++) {
  129. int expected_part_count = 0;
  130. if (ids[j].link_id != link_id ||
  131. ids[j].id.part_id != part_id ||
  132. ids[j].id.mfg_id != mfg_id ||
  133. ids[j].id.sdw_version != version)
  134. continue;
  135. /* find out how many identical parts are expected */
  136. for (k = 0; k < link->num_adr; k++) {
  137. u64 adr2 = link->adr_d[k].adr;
  138. if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
  139. expected_part_count++;
  140. }
  141. if (reported_part_count == expected_part_count) {
  142. /*
  143. * we have to check unique id
  144. * if there is more than one
  145. * Slave on the link
  146. */
  147. unique_id = SDW_UNIQUE_ID(adr);
  148. if (reported_part_count == 1 ||
  149. ids[j].id.unique_id == unique_id) {
  150. dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
  151. break;
  152. }
  153. } else {
  154. dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n",
  155. part_id, reported_part_count, expected_part_count, link_id);
  156. }
  157. }
  158. if (j == num_slaves) {
  159. dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
  160. return false;
  161. }
  162. }
  163. return true;
  164. }
  165. EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found);
  166. MODULE_LICENSE("GPL v2");
  167. MODULE_DESCRIPTION("ALSA SoC ACPI module");