* GPIO 1 -> DFS1 of AK5385
*/
+#include <linux/mutex.h>
#include <linux/pci.h>
+#include <sound/ac97_codec.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include "oxygen.h"
+#include "ak4396.h"
+#include "wm8785.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("C-Media CMI8788 driver");
{ OXYGEN_PCI_SUBID(0x13f6, 0x0010) },
{ OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
{ OXYGEN_PCI_SUBID(0x147a, 0xa017) },
- { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
- { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910) },
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 },
{ OXYGEN_PCI_SUBID(0x7284, 0x9761) },
#define GPIO_AK5385_DFS_DOUBLE 0x0001
#define GPIO_AK5385_DFS_QUAD 0x0002
-#define AK4396_WRITE 0x2000
-
-#define AK4396_CONTROL_1 0
-#define AK4396_CONTROL_2 1
-#define AK4396_CONTROL_3 2
-#define AK4396_LCH_ATT 3
-#define AK4396_RCH_ATT 4
-
-/* control 1 */
-#define AK4396_RSTN 0x01
-#define AK4396_DIF_MASK 0x0e
-#define AK4396_DIF_16_LSB 0x00
-#define AK4396_DIF_20_LSB 0x02
-#define AK4396_DIF_24_MSB 0x04
-#define AK4396_DIF_24_I2S 0x06
-#define AK4396_DIF_24_LSB 0x08
-#define AK4396_ACKS 0x80
-/* control 2 */
-#define AK4396_SMUTE 0x01
-#define AK4396_DEM_MASK 0x06
-#define AK4396_DEM_441 0x00
-#define AK4396_DEM_OFF 0x02
-#define AK4396_DEM_48 0x04
-#define AK4396_DEM_32 0x06
-#define AK4396_DFS_MASK 0x18
-#define AK4396_DFS_NORMAL 0x00
-#define AK4396_DFS_DOUBLE 0x08
-#define AK4396_DFS_QUAD 0x10
-#define AK4396_SLOW 0x20
-#define AK4396_DZFM 0x40
-#define AK4396_DZFE 0x80
-/* control 3 */
-#define AK4396_DZFB 0x04
-#define AK4396_DCKB 0x10
-#define AK4396_DCKS 0x20
-#define AK4396_DSDM 0x40
-#define AK4396_D_P_MASK 0x80
-#define AK4396_PCM 0x00
-#define AK4396_DSD 0x80
-
-#define WM8785_R0 0
-#define WM8785_R1 1
-#define WM8785_R2 2
-#define WM8785_R7 7
-
-/* R0 */
-#define WM8785_MCR_MASK 0x007
-#define WM8785_MCR_SLAVE 0x000
-#define WM8785_MCR_MASTER_128 0x001
-#define WM8785_MCR_MASTER_192 0x002
-#define WM8785_MCR_MASTER_256 0x003
-#define WM8785_MCR_MASTER_384 0x004
-#define WM8785_MCR_MASTER_512 0x005
-#define WM8785_MCR_MASTER_768 0x006
-#define WM8785_OSR_MASK 0x018
-#define WM8785_OSR_SINGLE 0x000
-#define WM8785_OSR_DOUBLE 0x008
-#define WM8785_OSR_QUAD 0x010
-#define WM8785_FORMAT_MASK 0x060
-#define WM8785_FORMAT_RJUST 0x000
-#define WM8785_FORMAT_LJUST 0x020
-#define WM8785_FORMAT_I2S 0x040
-#define WM8785_FORMAT_DSP 0x060
-/* R1 */
-#define WM8785_WL_MASK 0x003
-#define WM8785_WL_16 0x000
-#define WM8785_WL_20 0x001
-#define WM8785_WL_24 0x002
-#define WM8785_WL_32 0x003
-#define WM8785_LRP 0x004
-#define WM8785_BCLKINV 0x008
-#define WM8785_LRSWAP 0x010
-#define WM8785_DEVNO_MASK 0x0e0
-/* R2 */
-#define WM8785_HPFR 0x001
-#define WM8785_HPFL 0x002
-#define WM8785_SDODIS 0x004
-#define WM8785_PWRDNR 0x008
-#define WM8785_PWRDNL 0x010
-#define WM8785_TDM_MASK 0x1c0
+struct generic_data {
+ u8 ak4396_ctl2;
+};
static void ak4396_write(struct oxygen *chip, unsigned int codec,
u8 reg, u8 value)
static void ak4396_init(struct oxygen *chip)
{
+ struct generic_data *data = chip->model_data;
unsigned int i;
- chip->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+ data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
for (i = 0; i < 4; ++i) {
ak4396_write(chip, i,
AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
ak4396_write(chip, i,
- AK4396_CONTROL_2, chip->ak4396_ctl2);
+ AK4396_CONTROL_2, data->ak4396_ctl2);
ak4396_write(chip, i,
AK4396_CONTROL_3, AK4396_PCM);
ak4396_write(chip, i, AK4396_LCH_ATT, 0xff);
static void set_ak4396_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
+ struct generic_data *data = chip->model_data;
unsigned int i;
u8 value;
- value = chip->ak4396_ctl2 & ~AK4396_DFS_MASK;
+ value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
if (params_rate(params) <= 54000)
value |= AK4396_DFS_NORMAL;
- else if (params_rate(params) < 120000)
+ else if (params_rate(params) <= 108000)
value |= AK4396_DFS_DOUBLE;
else
value |= AK4396_DFS_QUAD;
- chip->ak4396_ctl2 = value;
+ data->ak4396_ctl2 = value;
for (i = 0; i < 4; ++i) {
ak4396_write(chip, i,
AK4396_CONTROL_1, AK4396_DIF_24_MSB);
static void update_ak4396_mute(struct oxygen *chip)
{
+ struct generic_data *data = chip->model_data;
unsigned int i;
u8 value;
- value = chip->ak4396_ctl2 & ~AK4396_SMUTE;
+ value = data->ak4396_ctl2 & ~AK4396_SMUTE;
if (chip->dac_mute)
value |= AK4396_SMUTE;
+ data->ak4396_ctl2 = value;
for (i = 0; i < 4; ++i)
ak4396_write(chip, i, AK4396_CONTROL_2, value);
}
.set_adc_params = set_wm8785_params,
.update_dac_volume = update_ak4396_volume,
.update_dac_mute = update_ak4396_mute,
- .used_channels = OXYGEN_CHANNEL_A |
- OXYGEN_CHANNEL_C |
- OXYGEN_CHANNEL_SPDIF |
- OXYGEN_CHANNEL_MULTICH |
- OXYGEN_CHANNEL_AC97,
- .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+ .model_data_size = sizeof(struct generic_data),
+ .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ PLAYBACK_2_TO_AC97_1 |
+ CAPTURE_0_FROM_I2S_1 |
+ CAPTURE_1_FROM_SPDIF |
+ CAPTURE_2_FROM_AC97_1,
+ .dac_channels = 8,
+ .function_flags = OXYGEN_FUNCTION_SPI |
+ OXYGEN_FUNCTION_ENABLE_SPI_4_5,
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
.set_adc_params = set_ak5385_params,
.update_dac_volume = update_ak4396_volume,
.update_dac_mute = update_ak4396_mute,
- .used_channels = OXYGEN_CHANNEL_B |
- OXYGEN_CHANNEL_C |
- OXYGEN_CHANNEL_SPDIF |
- OXYGEN_CHANNEL_MULTICH |
- OXYGEN_CHANNEL_AC97,
- .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+ .model_data_size = sizeof(struct generic_data),
+ .pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ PLAYBACK_2_TO_AC97_1 |
+ CAPTURE_0_FROM_I2S_2 |
+ CAPTURE_1_FROM_SPDIF |
+ CAPTURE_2_FROM_AC97_1,
+ .dac_channels = 8,
+ .misc_flags = OXYGEN_MISC_MIDI,
+ .function_flags = OXYGEN_FUNCTION_SPI |
+ OXYGEN_FUNCTION_ENABLE_SPI_4_5,
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
const struct pci_device_id *pci_id)
{
static int dev;
- const struct oxygen_model *model;
+ int is_meridian;
int err;
if (dev >= SNDRV_CARDS)
++dev;
return -ENOENT;
}
- model = pci_id->driver_data ? &model_meridian : &model_generic;
- err = oxygen_pci_probe(pci, index[dev], id[dev], 1, model);
+ is_meridian = pci_id->driver_data;
+ err = oxygen_pci_probe(pci, index[dev], id[dev],
+ is_meridian ? &model_meridian : &model_generic);
if (err >= 0)
++dev;
return err;