thinkpad_helper.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Helper functions for Thinkpad LED control;
  3. * to be included from codec driver
  4. */
  5. #if IS_ENABLED(CONFIG_THINKPAD_ACPI)
  6. #include <linux/acpi.h>
  7. #include <linux/thinkpad_acpi.h>
  8. static int (*led_set_func)(int, bool);
  9. static void (*old_vmaster_hook)(void *, int);
  10. static bool is_thinkpad(struct hda_codec *codec)
  11. {
  12. return (codec->core.subsystem_id >> 16 == 0x17aa) &&
  13. (acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") ||
  14. acpi_dev_found("IBM0068"));
  15. }
  16. static void update_tpacpi_mute_led(void *private_data, int enabled)
  17. {
  18. if (old_vmaster_hook)
  19. old_vmaster_hook(private_data, enabled);
  20. if (led_set_func)
  21. led_set_func(TPACPI_LED_MUTE, !enabled);
  22. }
  23. static void update_tpacpi_micmute(struct hda_codec *codec)
  24. {
  25. struct hda_gen_spec *spec = codec->spec;
  26. led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
  27. }
  28. static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
  29. const struct hda_fixup *fix, int action)
  30. {
  31. struct hda_gen_spec *spec = codec->spec;
  32. bool removefunc = false;
  33. if (action == HDA_FIXUP_ACT_PROBE) {
  34. if (!is_thinkpad(codec))
  35. return;
  36. if (!led_set_func)
  37. led_set_func = symbol_request(tpacpi_led_set);
  38. if (!led_set_func) {
  39. codec_warn(codec,
  40. "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
  41. return;
  42. }
  43. removefunc = true;
  44. if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
  45. old_vmaster_hook = spec->vmaster_mute.hook;
  46. spec->vmaster_mute.hook = update_tpacpi_mute_led;
  47. removefunc = false;
  48. }
  49. if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
  50. !snd_hda_gen_add_micmute_led(codec,
  51. update_tpacpi_micmute))
  52. removefunc = false;
  53. }
  54. if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
  55. symbol_put(tpacpi_led_set);
  56. led_set_func = NULL;
  57. old_vmaster_hook = NULL;
  58. }
  59. }
  60. #else /* CONFIG_THINKPAD_ACPI */
  61. static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
  62. const struct hda_fixup *fix, int action)
  63. {
  64. }
  65. #endif /* CONFIG_THINKPAD_ACPI */