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