From c626026dd72ec8363aaa862178adeacfa7ac09c5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 25 Jan 2008 08:41:52 +0100 Subject: [ALSA] add TempoTec HiFier driver Add a driver for the MediaTek/TempoTec HiFier Fantasia sound card. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/hifier.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 sound/pci/oxygen/hifier.c (limited to 'sound/pci/oxygen/hifier.c') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c new file mode 100644 index 000000000000..05ea2b65843e --- /dev/null +++ b/sound/pci/oxygen/hifier.c @@ -0,0 +1,207 @@ +/* + * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia + * + * Copyright (c) Clemens Ladisch + * + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this driver; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "oxygen.h" +#include "ak4396.h" + +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_DESCRIPTION("TempoTec HiFier driver"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "card index"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "enable card"); + +static struct pci_device_id hifier_ids[] __devinitdata = { + { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, + { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, + { } +}; +MODULE_DEVICE_TABLE(pci, hifier_ids); + +struct hifier_data { + u8 ak4396_ctl2; +}; + +static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) +{ + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CLOCK_320 | + (0 << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI, + AK4396_WRITE | (reg << 8) | value); +} + +static void hifier_init(struct oxygen *chip) +{ + struct hifier_data *data = chip->model_data; + + data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL; + ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); + ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); + ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); + ak4396_write(chip, AK4396_LCH_ATT, 0xff); + ak4396_write(chip, AK4396_RCH_ATT, 0xff); + + snd_component_add(chip->card, "AK4396"); + snd_component_add(chip->card, "CS5340"); +} + +static void hifier_cleanup(struct oxygen *chip) +{ +} + +static void set_ak4396_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct hifier_data *data = chip->model_data; + u8 value; + + value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; + if (params_rate(params) <= 54000) + value |= AK4396_DFS_NORMAL; + else if (params_rate(params) < 120000) + value |= AK4396_DFS_DOUBLE; + else + value |= AK4396_DFS_QUAD; + data->ak4396_ctl2 = value; + ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); + ak4396_write(chip, AK4396_CONTROL_2, value); + ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); +} + +static void update_ak4396_volume(struct oxygen *chip) +{ + ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); + ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); +} + +static void update_ak4396_mute(struct oxygen *chip) +{ + struct hifier_data *data = chip->model_data; + u8 value; + + value = data->ak4396_ctl2 & ~AK4396_SMUTE; + if (chip->dac_mute) + value |= AK4396_SMUTE; + data->ak4396_ctl2 = value; + ak4396_write(chip, AK4396_CONTROL_2, value); +} + +static void set_cs5340_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ +} + +static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); + +static int hifier_control_filter(struct snd_kcontrol_new *template) +{ + if (!strcmp(template->name, "Master Playback Volume")) { + template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + template->tlv.p = ak4396_db_scale; + } else if (!strcmp(template->name, "Stereo Upmixing")) { + return 1; /* stereo only - we don't need upmixing */ + } else if (!strcmp(template->name, + SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK)) || + !strcmp(template->name, + SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) { + return 1; /* no digital input */ + } + return 0; +} + +static int hifier_mixer_init(struct oxygen *chip) +{ + return 0; +} + +static const struct oxygen_model model_hifier = { + .shortname = "C-Media CMI8787", + .longname = "C-Media Oxygen HD Audio", + .chip = "CMI8788", + .init = hifier_init, + .control_filter = hifier_control_filter, + .mixer_init = hifier_mixer_init, + .cleanup = hifier_cleanup, + .set_dac_params = set_ak4396_params, + .set_adc_params = set_cs5340_params, + .update_dac_volume = update_ak4396_volume, + .update_dac_mute = update_ak4396_mute, + .model_data_size = sizeof(struct hifier_data), + .dac_channels = 2, + .used_channels = OXYGEN_CHANNEL_A | + OXYGEN_CHANNEL_SPDIF | + OXYGEN_CHANNEL_MULTICH, + .function_flags = 0, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +static int __devinit hifier_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + ++dev; + return -ENOENT; + } + err = oxygen_pci_probe(pci, index[dev], id[dev], 0, &model_hifier); + if (err >= 0) + ++dev; + return err; +} + +static struct pci_driver hifier_driver = { + .name = "CMI8787HiFier", + .id_table = hifier_ids, + .probe = hifier_probe, + .remove = __devexit_p(oxygen_pci_remove), +}; + +static int __init alsa_card_hifier_init(void) +{ + return pci_register_driver(&hifier_driver); +} + +static void __exit alsa_card_hifier_exit(void) +{ + pci_unregister_driver(&hifier_driver); +} + +module_init(alsa_card_hifier_init) +module_exit(alsa_card_hifier_exit) -- cgit v1.2.2 From 236c4920ea825acbffa7bbba24c182ec6a9a8245 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Jan 2008 08:32:58 +0100 Subject: [ALSA] oxygen: fix AK4396 double rate upper limit Fix the upper sample rate limit for the double rate mode of the AK4396 to the value from the datasheet. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/hifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/oxygen/hifier.c') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 05ea2b65843e..51c4d1ae9d02 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -90,7 +90,7 @@ static void set_ak4396_params(struct oxygen *chip, 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; -- cgit v1.2.2 From 2ea85986dd1fa96ccf0a2f37877d58a57ff6f583 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 30 Jan 2008 08:38:30 +0100 Subject: [ALSA] oxygen: revert SPI clock frequency change for AK4396/WM8785 While the AK4396 and WM8785 datasheets say that the SPI clock cycle length must be at least 200 ns, 320 ns seems not to work reliably with the controller, so we better use 160 ns. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela --- sound/pci/oxygen/hifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/oxygen/hifier.c') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 51c4d1ae9d02..3ea1f05228a1 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -56,7 +56,7 @@ static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) { oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | OXYGEN_SPI_DATA_LENGTH_2 | - OXYGEN_SPI_CLOCK_320 | + OXYGEN_SPI_CLOCK_160 | (0 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, AK4396_WRITE | (reg << 8) | value); -- cgit v1.2.2