se6x.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * C-Media CMI8787 driver for the Studio Evolution SE6X
  4. *
  5. * Copyright (c) Clemens Ladisch <[email protected]>
  6. */
  7. /*
  8. * CMI8787:
  9. *
  10. * SPI -> microcontroller (not actually used)
  11. * GPIO 0 -> do.
  12. * GPIO 2 -> do.
  13. *
  14. * DAC0 -> both PCM1792A (L+R, each in mono mode)
  15. * ADC1 <- 1st PCM1804
  16. * ADC2 <- 2nd PCM1804
  17. * ADC3 <- 3rd PCM1804
  18. */
  19. #include <linux/pci.h>
  20. #include <linux/module.h>
  21. #include <sound/core.h>
  22. #include <sound/control.h>
  23. #include <sound/initval.h>
  24. #include <sound/pcm.h>
  25. #include "oxygen.h"
  26. MODULE_AUTHOR("Clemens Ladisch <[email protected]>");
  27. MODULE_DESCRIPTION("Studio Evolution SE6X driver");
  28. MODULE_LICENSE("GPL v2");
  29. static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  30. static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
  31. static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
  32. module_param_array(index, int, NULL, 0444);
  33. MODULE_PARM_DESC(index, "card index");
  34. module_param_array(id, charp, NULL, 0444);
  35. MODULE_PARM_DESC(id, "ID string");
  36. module_param_array(enable, bool, NULL, 0444);
  37. MODULE_PARM_DESC(enable, "enable card");
  38. static const struct pci_device_id se6x_ids[] = {
  39. { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
  40. { }
  41. };
  42. MODULE_DEVICE_TABLE(pci, se6x_ids);
  43. static void se6x_init(struct oxygen *chip)
  44. {
  45. oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005);
  46. snd_component_add(chip->card, "PCM1792A");
  47. snd_component_add(chip->card, "PCM1804");
  48. }
  49. static int se6x_control_filter(struct snd_kcontrol_new *template)
  50. {
  51. /* no DAC volume/mute */
  52. if (!strncmp(template->name, "Master Playback ", 16))
  53. return 1;
  54. return 0;
  55. }
  56. static void se6x_cleanup(struct oxygen *chip)
  57. {
  58. }
  59. static void set_pcm1792a_params(struct oxygen *chip,
  60. struct snd_pcm_hw_params *params)
  61. {
  62. /* nothing to do (the microcontroller monitors DAC_LRCK) */
  63. }
  64. static void set_pcm1804_params(struct oxygen *chip,
  65. struct snd_pcm_hw_params *params)
  66. {
  67. }
  68. static unsigned int se6x_adjust_dac_routing(struct oxygen *chip,
  69. unsigned int play_routing)
  70. {
  71. /* route the same stereo pair to DAC0 and DAC1 */
  72. return ( play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
  73. ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK);
  74. }
  75. static const struct oxygen_model model_se6x = {
  76. .shortname = "Studio Evolution SE6X",
  77. .longname = "C-Media Oxygen HD Audio",
  78. .chip = "CMI8787",
  79. .init = se6x_init,
  80. .control_filter = se6x_control_filter,
  81. .cleanup = se6x_cleanup,
  82. .set_dac_params = set_pcm1792a_params,
  83. .set_adc_params = set_pcm1804_params,
  84. .adjust_dac_routing = se6x_adjust_dac_routing,
  85. .device_config = PLAYBACK_0_TO_I2S |
  86. CAPTURE_0_FROM_I2S_1 |
  87. CAPTURE_2_FROM_I2S_2 |
  88. CAPTURE_3_FROM_I2S_3,
  89. .dac_channels_pcm = 2,
  90. .function_flags = OXYGEN_FUNCTION_SPI,
  91. .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
  92. .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
  93. .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
  94. .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S,
  95. };
  96. static int se6x_get_model(struct oxygen *chip,
  97. const struct pci_device_id *pci_id)
  98. {
  99. chip->model = model_se6x;
  100. return 0;
  101. }
  102. static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
  103. {
  104. static int dev;
  105. int err;
  106. if (dev >= SNDRV_CARDS)
  107. return -ENODEV;
  108. if (!enable[dev]) {
  109. ++dev;
  110. return -ENOENT;
  111. }
  112. err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
  113. se6x_ids, se6x_get_model);
  114. if (err >= 0)
  115. ++dev;
  116. return err;
  117. }
  118. static struct pci_driver se6x_driver = {
  119. .name = KBUILD_MODNAME,
  120. .id_table = se6x_ids,
  121. .probe = se6x_probe,
  122. #ifdef CONFIG_PM_SLEEP
  123. .driver = {
  124. .pm = &oxygen_pci_pm,
  125. },
  126. #endif
  127. .shutdown = oxygen_pci_shutdown,
  128. };
  129. module_pci_driver(se6x_driver);